赞
踩
项目做好以后,在上线之前还有一些工作需要去做:
压缩css
压缩js
压缩图片
编译sass
合并文件
。。。
等等,在前端工作流出现之前,这些工作都由人力完成,而这些工作往往比写业务本身更加费时,效率非常之低且还容易出错,于是自动化的处理工具也就必然出现了。
前端的构建工具常见的有Grunt、Gulp、Webpack三种,Grunt比较老旧,功能少,更新少,插件少。gulp适用于原生项目的打包,但是在现代的工作中使用非常少。webpack通常被用在框架中,使用量很大,所以我们学习webpack。
打包的步骤,其实就是在命令行窗口执行命令,这个命令需要我们在package.json文件中进行配置:
- {
- "scripts": {
- "compact": "webpack --config webpack.config.js"
- },
- "name": "webpackstudy",
- "version": "1.0.0",
- "main": "peizhi.js",
- "devDependencies": {},
- "author": "",
- "license": "ISC",
- "description": ""
- }
其中compact其实就是我们最终要执行的命令,执行如下:
npm run compact
但实际上运行的是compact键对应的命令:
webpack --config webpack配置文件
这行命令中,可以看出,webpack就是我们实际上要运行的命令。
这个命令我们在计算机上默认是不存在的:
需要进行下载,下载命令:
npm i webpack-cli -D
在package.json中可以看到下载成功:
- {
- "dependencies": {
- "webpack-cli": "^4.9.2"
- },
- "scripts": {
- "compact": "webpack --config webpack.config.js"
- },
- "name": "webpackstudy",
- "version": "1.0.0",
- "main": "peizhi.js",
- "devDependencies": {},
- "author": "",
- "license": "ISC",
- "description": ""
- }
这时候执行命令还是不成功的
因为我们还没有定义webpack的配置文件。配置文件中需要指定打包哪些文件,打包到哪里。。。
文件名称一种使用webpack默认的配置文件名称,另一种就是使用自定义的文件名称,这两种文件名称在使用的稍有区别:
webpack默认的配置文件名称:webpack.config.js,我们在scripts中自定义的命令中,可以省略--config的配置项,只要有webpack就ok:
- {
- "dependencies": {
- "webpack-cli": "^4.9.2"
- },
- "scripts": {
- "compact": "webpack"
- },
- "name": "webpackstudy",
- "version": "1.0.0",
- "main": "peizhi.js",
- "devDependencies": {},
- "author": "",
- "license": "ISC",
- "description": ""
- }
当然加上也是可以的。
使用自定义的文件名称,就必须在scripts自定义的命令中,添加--config的配置项:
- {
- "dependencies": {
- "webpack-cli": "^4.9.2"
- },
- "scripts": {
- "compact": "webpack --config peizhi.js"
- },
- "name": "webpackstudy",
- "version": "1.0.0",
- "main": "peizhi.js",
- "devDependencies": {},
- "author": "",
- "license": "ISC",
- "description": ""
- }
scripts中的命令:compact是自定义的,可以随便起名字,通常运行的命令为:
npm run 命令名称
如果我们配置的命令名称为:start或stop或restart或test,那在运行的时候可以省略run:
- npm start
- npm test
- npm restart
- npm stop
命令做好以后,需要在配置文件中进行配置。
因为webpack是基于nodejs环境运行的打包工作,所以配置文件要遵循nodejs的模块化语法,配置文件的配置格式如下:
-
- module.exports= {
- // 所有配置都在这里定义
- }
'运行
具体的配置,也就是说我们打包什么,还需要准备。
在我们准备之前执行命令:
npm run compact
执行结果:
报错了,找不到src文件夹,为什么呢?
因为webpack默认的打包规则如下:
默认会打包src文件夹下的index.js文件
默认会将结果打包dist文件夹中,如果dist文件夹不存在,会自动创建
默认会将打包好的文件命名为main.js
接下来,我们就要创建src文件夹,新建index.js文件,在其中写入一些代码:
-
- for(let i=1; i<=3; i++) {
- setTimeout(function() {
- console.log(i);
- }, 1000*i)
- }
'运行
执行命令后,打包生成的结果如下:
如果不配置入口文件,默认会打包src文件夹下的index.js文件,如果要打包其他文件,就需要进行配置:
entry: 入口文件路径
例:我们打包src文件夹下的test.js
-
- module.exports= {
- // 所有配置都在这里定义
- entry: './src/test.js'
- }
'运行
打包结果:
entry的值还可以是一个对象,表示多入口:
-
- entry: {
- app: './src/app.js',
- adminApp: './src/adminApp.js',
- },
如果不配置出口文件,默认会将打包结果放在dist文件夹下的main.js文件中,如果希望生成的目标文件在别的文件夹下,换个新的文件名称,就需要配置出口文件:
-
- output: {
- path: 文件夹路径,
- filename: 文件名称,
- clean: true, // 是否每次清空目标文件夹
- }
例:将目标文件放在dest文件夹下的target.js文件中
-
- output: {
- path: 'dest',
- filename: 'target.js'
- }
执行结果:
要求我们配置的dest目标文件夹必须是绝对路径,所以重新修改路径如下:
-
- module.exports= {
- // 所有配置都在这里定义
- entry: './src/test.js',
- output: {
- path: __dirname+'/dest', // 这里必须是绝对路径
- filename: 'target.js'
- }
- }
'运行
重新执行命令,打包结果如下:
在多入口的情况,filename的值,可以换成[contenthash]或[name],打包的时候,使用系统创建的随机名称([contenthash])或跟源文件相同的文件名称([name])。
打包模式分两种,分别是开发模式和生产模式。区别如下:
production是生产模式,会把打包好后的代码进行压缩,可阅读性不好,但是代码体积小
development是开发模式,不会压缩代码,可阅读性好,但是代码体积大
默认打包规则是生产模式,如果要指定打包模式,需要配置:
mode: development/production
例:将默认的生产模式换成开发模式
-
- module.exports= {
- // 所有配置都在这里定义
- entry: './src/index.js',
- output: {
- path: __dirname+'/dest',
- filename: 'target.js'
- },
- // 打包模式
- mode: 'development'
- }
'运行
打包的目标文件结果:
从上图中可以看出,打包的最终结果,不再是压缩形式的,这是开发模式的打包。
前面每次打包的警告就是表示我们没有配置打包模式
如果打包好的文件在运行的时候报错了,报错在打包的文件中,我们很难找到错误的地方和原因,因为打包生成的文件不是我们手写的,是机器生成的,为了能将错误定位在源文件中,我们需要添加map文件配置:
devtool:"source-map"
如果在我们运行的目标文件中报错了,可以通过这个文件准确的定位到错误的源文件。
webpack默认只能打包js文件,如果要处理html文件或其他文件的操作都需要依赖插件
-
- plgins: [
- 插件配置
- ]
插件名称:html-webpack-plugin
下载:npm i html-webpack-plugin
导入:
-
- const htmlwebpackplugin=require('html-webpack-plugin')
插件配置:
-
- const htmlwebpackplugin=require('html-webpack-plugin')
- module.exports= {
- // 所有配置都在这里定义
- entry: './src/index.js',
- output: {
- path: __dirname+'/dest',
- filename: 'target.js'
- },
- // 打包模式
- mode: 'development',
- // 插件配置
- plugins: [
- // html插件
- newhtmlwebpackplugin({
-
- })
- ]
- }
默认会在目标文件夹中生成index.html文件,并将我们打包好的js文件注入到这个html中:
如果要打包一个html文件,或对目标html进行其他配置,配置项如下:
- template: 要打包的html文件,
- filename: 生成的目标文件路径,
- hash: 是否为所有注入的静态资源添加webpack每次编译产生的唯一hash值,
- inject: 向template或者templateContent中注入所有静态资源,不同的配置值注入的位置不经相同,
- 取值:
- body:所有JavaScript资源插入到body元素的底部
- true或者head: 所有JavaScript资源插入到head元素中-默认
- false:所有静态资源css和JavaScript都不会注入到模板文件中
- favicon: 添加特定favicon路径到输出的html文档中,
- title: 生成的html文档的标题。配置该项,它并不会替换指定模板文件中的title元素的内容,
- chunks: 值是数组,指定我们要注入的入口
配置项测试:
-
- new htmlwebpackplugin({
- title: '我打包生成的首页'
- })
打包后结果:
-
- new htmlwebpackplugin({
- title: '我打包生成的首页',
- template: './src/home.html'
- })
在src下新建home.html,内容如下:
- <!DOCTYPE html>
- <htmllang="en">
- <head>
- <metacharset="UTF-8">
- <title>测试网页</title>
- </head>
- <body>
- 哈哈
- </body>
- </html>
打包结果:
title选项是不会改变原网页中标题的,只有在没有原网页,需要创建一个html的时候,指定title才有用。
如果指定了template选项后,不会自动创建html文件,是将指定的html页面打包到目标文件夹中。
-
- new htmlwebpackplugin({
- title: '我打包生成的首页',
- template: './src/home.html',
- favicon: './src/favicon.ico'
- })
给src文件夹下放一个网站图标,打包结果:
-
- new htmlwebpackplugin({
- title: '我打包生成的首页',
- template: './src/home.html',
- favicon: './src/favicon.ico',
- filename: 'my.html'
- })
会将template打包生成新的文件名称:my.html,如下图:
默认为true/'head',表示要将打包后的js文件注入到html中,且放在html头部head标签中,false表示不注入,'body'表示将打包后的js文件引入到html的body标签中。
默认值为false,当设置为true的时候,打包后的html引入的静态文件,会在地址后面添加随机的参数,目的是为了避免浏览器缓存。
设置为true的时候,生成的html如下:
chunks选项适用于多入口且多html的时候,我们希望某些html引入不同的入口中的内容,就给当前html插件配置chunks选项:
-
- plugins: [
- new htmlwebpackplugin({
- title: '我打包生成的首页',
- template: './src/home.html',
- favicon: './src/favicon.ico',
- filename: 'my.html',
- chunks: [entry的入口键, entry中的入口键]
- }),
- new htmlwebpackplugin({
- title: '我打包生成的列表页',
- template: './src/a.html',
- favicon: './src/favicon.ico',
- filename: 'b.html',
- chunks: [entry的入口键, entry中的入口键]
- })
- ]
我们在开发过程中,有些文件是需要拷贝到目标文件夹中的,因为此时只能打包js文件和html文件,css和其他js文件是不能进行打包的,也拷贝不到目标文件夹中 - 静态css,所以将来打包后的html是会运行报错的,此时就需要用到另外一个插件:
npm i copy-webpack-plugin@6.4.1 -D
导入并使用:
-
- const CopyPlugin=require("copy-webpack-plugin");
- // 在插件配置中使用
- new CopyPlugin({
- // 插件配置 from从某文件夹复制,可以使用相对路径;to到某文件夹,尽量使用绝对路径,使用相对路径的时候是相对上面设置好的输出目录
- patterns: [
- { "from": "./public/img", "to": path.join(__dirname, "./dist/img/") },
- { "from": "./public/css", "to": path.join(__dirname, "./dist/css/") },
- { "from": "./public/js", "to": path.join(__dirname, "./dist/js/") },
- { "from": "./public/fonts", "to": path.join(__dirname, "./dist/fonts/") }
- ]
- }),
如果在html页面中,引入了css文件、图片等静态资源,打包后的html页面中同样保持引入的关系,但是css文件、图片等静态资源没有被打包到目标文件夹中,导致html文件无法出现正常效果。
要将css文件、图片等静态资源一起打包目标文件夹中,就需要使用解析器来处理。
解析器配置:
-
- module:{
- rules: [
- 解析器的配置
- ]
- }
不同的静态资源处理需要使用不同的解析器。
css解析器需要下载两个插件:npm i css-loader style-loader
css-loader插件起到的作用是将入口文件中css进行打包
style-loader插件起到的作用是将打包好的css引入到html中
下载好后不需要导入,但是需要配置:
-
- module: {
- rules: [
- {
- // 匹配到.css的文件后缀就进行处理
- test: /\.css/,
- // 使用两个插件进行处理
- use: ['style-loader', 'css-loader']
- }
- ]
- }
'运行
光有这样的配置是不行的,因为webpack默认打包的是入口文件,所有内容都要放在入口文件中导入才能被打包,所以我们需要将静态资源在入口文件中导入:
-
- require('./css/test.css')
这样就可以了。最终打开打包后的html页面,css样式效果能正常展示在浏览器中了。
当我们打开目标文件夹后,发现css文件并没有在目标文件夹中,那是因为默认将css样式打包在出口js文件中了。
在实际项目中,我们还是希望能将css单独放在一个文件中,不希望都放在出口js文件中,这时就需要一个插件来处理了
插件名称:mini-css-extract-plugin
下载:npm i mini-css-extract-plugin
导入:
-
- const MiniCssExtractPlugin=require('mini-css-extract-plugin');
配置这个插件:
-
- new MiniCssExtractPlugin({
- // 生成的文件名
- filename:'css/[hash].css'
- })
如果不设置文件名称,最终会默认生成main.css。
配置好以后,在解析器中用这个插件替换style-loader插件:
-
- {
- test: /\.css/,
- use: [MiniCssExtractPlugin.loader, 'css-loader']
- }
此时重新打包就可以在目标文件夹中生成,css文件夹,目标css文件就在css文件中。出口文件中也就没有css的代码了。
sass文件需要进行编译,还要被引入到html文件中使用,需要依赖两个插件:npm i sass sass-loader,下载成功后同样不需要导入,只需要配置解析器就好:
-
- {
- test: '\.scss',
- use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader']
- }
同样的sass文件也要在入口文件被导入才能被解析:
-
- require('./css/test.css')
- require('./sass/test.scss')
下载插件:
npm i babel-loader @babel/core @babel/preset-env @babel/runtime @babel/plugin-transform-runtime
配置loader:
-
- {
- test: /\.js$/,
- exclude: /node_modules/,
- use: {
- loader: 'babel-loader',
- options: {
- presets: ['@babel/preset-env'],
- plugins: [
- [
- '@babel/plugin-transform-runtime'
- ]
- ]
- }
- }
- }
需要依赖1个插件:html-loader:
下载:npm i html-loader
使用配置:
首先修改导出文件目录:
-
- output: {
- path: __dirname+'/dest',
- filename: 'target.js',
- clean: true,
- assetModuleFilename: 'img/[name][ext]'
- }
然后添加图片解析器:
-
- {
- test: /\.png$/,
- type: 'asset/resource', // 专门用于打包静态资源的内置解析器
- generator: {
- filename: 'static/[hash][ext][query]'
- }
- },
- {
- test: /\.html$/,
- loader: 'html-loader',
- options: {
- esModule: false
- }
- },
不管是css中引入的图片还是html中引入的图片都可以进行打包了。
压缩css需要依赖插件。
插件名称:css-minimizer-webpack-plugin
导入:npm i css-minimizer-webpack-plugin
使用:
-
- optimization: {
- minimizer: [
- new CssMinimizerWebpackPlugin()
- ]
- }
注意:这个插件需要将mode设置为生产模式的时候生效。
-
- optimization: {
- splitChunks: {
- chunks: 'all'
- }
- }
'运行
如果希望我们的项目运行在一个web服务器中,webpack也有对应的插件让我们可以快速启动一个web服务器,且这个插件还可以让我们的项目自动刷新。
插件名称:webpack-dev-server
下载:npm i webpack-dev-server
这个插件不需要导入,直接使用:
-
- devServer: {
- static: {
- directory: path.join(__dirname, 'dest'),
- }
- }
这个web服务器要启动起来要再次执行一个命令:
webpack serve --config peizhi.js --open
后面--open参数是自动打开浏览器的。
其他配置参考网址:DevServer | webpack
注意
loader 是使 webpack 拥有加载和解析非 js 文件的能力,例如图片、CSS、字体等,可以将它们打包到最终的 JavaScript 代码中或者作为单独的文件输出,使得开发者可以通过 JavaScript 模块化的方式来管理这些资源,提高开发效率和代码可维护性。例如,webpack 中常用的 loader 有 css-loader、file-loader、url-loader 等。每个 loader 只关注一个文件类型,将文件转换为合法的模块,并返回处理后的代码。
uglifyJsPlugin 是用于压缩 js 代码的 webpack 插件。它可以将代码中的空格、注释、无效代码等进行压缩,从而减小文件的大小,提高加载速度。uglifyJsPlugin是一个可以在webpack构建过程中使用的插件,通过配置webpack配置文件中的plugins选项启用,同时可以通过传递参数来控制压缩的程度和详细程度。
uglifyJsPlugin 压缩 js 代码的原理是将代码进行 AST(抽象语法树)解析,将代码中的语句节点逐个进行分析,然后根据一些预定义的规则进行代码转换和优化,从而得到更加紧凑的代码。同时,在压缩过程中,需要注意保留代码中的一些特殊用途的语句节点,例如require、module等模块导入导出语句节点等。
使用 PostCSS 来为 CSS 代码自动添加适应不同浏览器的 CSS 前缀。PostCSS 是一个基于 JavaScript 的 CSS 处理器,它可以帮助你自动为 CSS 代码添加适应不同浏览器的 CSS 前缀。使用 PostCSS 可以大大简化编写 CSS 代码的过程,使得代码更加简洁、易读,并且具有很强的可维护性。
以下是如何使用 PostCSS 为 CSS 代码自动添加适应不同浏览器的 CSS 前缀的步骤:
安装 PostCSS
你可以使用 npm 安装 PostCSS:
npm install postcss --save-dev
同时,你也需要安装适用于 PostCSS 的一个前缀插件 autoprefixer:
npm install autoprefixer --save-dev
配置 PostCSS
要配置 PostCSS,你需要在项目根目录下创建一个名为 postcss.config.js 的文件,并将以下代码复制到该文件中:
module.exports = { plugins: [ require('autoprefixer') ]}
这告诉 PostCSS ,要使用 autoprefixer 插件来自动添加浏览器前缀。
在项目中使用 PostCSS
现在,你可以在项目中使用 PostCSS 来自动添加浏览器前缀了。你可以使用 gulp 或者 webpack 等构建工具来实现这一步骤。
例如,如果你使用 gulp ,你可以在 gulpfile.js 文件中编写以下代码:
-
- const gulp = require('gulp');
- const postcss = require('gulp-postcss');
- const autoprefixer = require('autoprefixer');
- gulp.task('css', function () {
- return gulp.src('./src/*.css').pipe(postcss([autoprefixer])).
- pipe(gulp.dest('./dist'));
- });
这会告诉 gulp 从 src 目录中读取 CSS 文件,并使用 autoprefixer 插件为代码自动添加浏览器前缀,最后将处理过的文件输出到 dist 目录中。
现在,你已经成功地为 CSS 代码自动添加了适应不同浏览器的 CSS 前缀。如果你运行项目并检查生成的 CSS 文件,你将看到所有必要的前缀已经被添加了。
Babel 是 webpack 的一个插件。它可以将 ES6+ 的代码转换成 ES5 兼容的代码,从而可以在老版本的浏览器中运行。同时,Babel 还支持 TypeScript、React 等的转换。通过在 webpack 配置中添加 Babel 插件,可以让 webpack 对 ES6+ 代码进行自动转换。
Babel 是一个 JavaScript 编译器,可以将高版本的 JavaScript 代码转换成低版本的 JavaScript 代码,以实现在旧版浏览器中也能够运行的效果。Babel 是 webpack 的一个常用插件之一,用于将 ES6 以上版本的 JavaScript 代码转换成 ES5 以下的代码。这样可以确保应用在各种浏览器和环境下都能够正常运行。Babel 的一个主要功能是转换 JavaScript 的语法,包括箭头函数、模板字符串、解构赋值、Promise 等,并且还能够转换新的 API,如 Set、Map、Symbol 等。通过 Babel 插件的配置,我们还可以针对不同的编译目标设置不同的转换方式和插件。
1. HTML文档结构:一个Webpage的基本配置从HTML文档的结构开始。HTML文档由<!DOCTYPE>声明、<html>元素、<head>头部和<body>主体组成。
2. 页面标题:通过在<head>标签中使用<title>标签,设置页面的标题,该标题将显示在浏览器的标题栏或标签页上。
3. 字符编码:使用<meta>标签设置字符编码,例如:<meta charset="UTF-8">,以确保页面能正确解析特定字符集的文本内容。
4. 视口设置:在移动设备上,可以使用<meta>标签设置视口(viewport)的大小和缩放,以适应不同的屏幕尺寸。
- 首先我们可以缩小搜索的范围 通过配置 alias 还有 extensions
- 减少需要解析的文件 noparse 配置告诉 webpack 哪些文件是可以忽略的 不进行解析
- 避免重复编译第三方库 单独放在一个页面中 不会跟着业务代码重新打包
- 打包 js 代码压缩时是单线程的 使用 parallelUglifyPlugin 插件开启多个子进程 采用并行方式对多个文件进行压缩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。