一、不能被浏览器识别的一些内容
我们最常用的就是ES6的模块化语法,那么我们来实验一下,确实是会报错的
二、使用编译工具编译成浏览器能识别的语法
初始化我们的代码成为包管理项目,使用npm init -y,会生成package.json(包描述文件),特别注意这里的包名不能和我们需要下载的任意包名重复;注意package文件中的main需要和自己的入口文件匹配;然后下载webpack和webpack-cli
在我们还没有配置webpack.config文件的时候可以使用npx去运行node_modules中运用程序(将bin添加到环境变量),使用 npx webpack ./src/main.js --mode=development;先使用开发者模式打包;打包还是很快的;这时在index.html中引入打包后的文件,浏览器就不会报错了
三、开发者模式和生产模式的代码比较
开发者模式:会发现每一个模块都被eval函数包裹,并且ES6的一些语法是没有被转化的
生产模式:发现代码非常简介,使用一个匿名函数防止变量冲突,我们的减法模块直接就给个结果,能压缩的就压缩;加法直接就变成了一个运算
四、webpack只认识JS和JSON
尝试引入css打包试一下,webpack中没有被依赖和引入的文件是不会打包的,确实是不认识的
五、使用配置文件配置css-loader和style-loader
配置文件必须叫webpack.config.js,位置和package.json文件一个层级;我们的webpack是在node环境下运行的,所以需要采用commonJS的写法,webpack的五大核心概念就是配置文件中的基石,然后在loader中配置css-loader,参照官方文档,文档中只安装css-loader是不够的还需要style-loader
webpack在读取loader时是从右往左读,css-loader是将css样式变成一个JS模块,style-loader是动态创建style标签,在public下面的index.html中是没有的,是动态创建
const path = require('path');
module.exports = {
// 入口需要使用相对路径
entry:'./src/main.js',
output:{
// path需要使用绝对路径,__dirname是当前目录,所以这里是当前目录下的dist文件
path:path.resolve(__dirname,'dist'),
// 输出文件名是main.js
filename:'main.js',
// 自动清空上次打包目录
clean:true
},
// 配置loader
module:{
rules: [
{
// 只检查css文件
test: /.css$/,
use: ["style-loader", "css-loader"],
},
],
},
// 配置插件
plugins:[],
// 打包模式
mode:'production',
}
六、使用mini-css-extract-plugin提取css样式
使用style-loader是利用js创建style标签去引入css样式的,这样就需要将js解析完才可以出样式,会很容易形成闪屏现象,将我们浏览器的网速调慢就会出现,所以需要使用mini-css-extract-plugin提取css单独的文件,然后手动引入即可,参照官网配置webpack.docschina.org/plugins/min…;这里我们使用生产环境进行打包,发现样式是没有进行压缩的
七、使用css-minimizer-webpack-plugin进行css压缩
上面提取了样式但是没有压缩,所以这里使用一个插件进行压缩,使用参照官网webpack.docschina.org/plugins/css…
mini-css-extract-plugin需要引入、在plugins中new、然后在loader中替换style-loader
css-minimizer-webpack-plugin只需要引入和在plugins中new即可
还可以使用postcss-loader给css加上前缀来保证兼容性
八、清空打包内容
webpack4清空打包内容需要使用clean-webpack-plugin;webpack5只需要在输出中配置clean即可
九、处理图片资源;音视频、字体图标都是使用资源配置可以解决
webpack4中需要使用file-loader和url-loader处理图片资源,webpack5已经将两个loader内置到webpack中了,不需要下载可以直接使用,不用配置也可以直接使用,但是如果想让转换base64才需要配置;base64的体积比原图的体积会大,所以一般将小图转换成base64,一般小于8k才转换;配置方式在官网中搜索资源模块下面去找一下;
默认打包出来的内容目录是平铺的,想要对目录进行划分,需要修改输出路径,在配置loader的地方配置filename
{
// ?表示可以有可以没有
test: /.(png|jpe?g|svg|webp|gif)/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8 * 1024 // 小于8kb转base64,减少请求但是体积变大
}
},
generator: {
// hash是生成的hash值,价格:是表示取几位,相当于根据内容计算,ext是后缀,query是后缀之后的内容一般不用
filename: 'images/[hash:8][ext][query]'
}
}
十、处理JS中的新增语法——Eslint和babel的配置
Eslint
可以用来检查JS和JSX语法,也就是可以检查react而不能检查vue,要检查vue需要添加其他的loader,具体的Eslint规则可以参照官网eslint.cn/docs/rules/;自己写的规则比继承的规则优先级高;webpack4是使用loader进行处理,webpack5使用的是插件进行处理
使用方式参照官网,webpack.docschina.org/plugins/esl…,主要的步骤是安装eslint以及eslint插件,在webpack.config中配置插件,然后在webpack.config.js同级目录添加eslint的配置文件,配置文件的命名规则是.eslintrc.,后面的可以不带,也可以是js文件或者json文件,我们是使用js文件比较多
module.exports = {
// 继承eslint的规则
extends:["eslint:recommended"],
// 指定环境变量
env:{
node:true, //启用node中的全局变量
browser:true // 启用浏览器中的全局变量比如console
},
// 语法环境,默认支持ES5想要支持ES6需要配置一下
parserOptions:{
ecmaVersion:6,
sourceType:"module"
},
// 这里可以配置自己的一些规则
rules:{
"no var":2
}
}
Babel
babel-loader在不加预设(插件)的情况下是没有什么作用的,所以可以按需去下载预设再配置,可以参照webpack.docschina.org/loaders/bab…官网配置
@babel/preset-env:用于将ES6语法转换成ES5语法,是一个智能预设
@babel/preset-react:用来编译JSX语法
@babel/preset-typescript:用来编译TS语法
特别注意:使用了智能预设只能转换简单的es6语法,如let、const、箭头函数,不能转换promise等;所以需要使用core-js,使用参照juejin.cn/post/716841…
可以看到promise语法还在,扩展运算符不在,下面是使用了core-js的打包截图
可以看到promise是被core-js重写了并且引入,也可以看到babel为每个文件注入一些辅助代码,默认情况下会添加到每个文件中,这样如果处理的文件特别多那么打包体积会增加,所以可以将这些辅助代码提成一个独立的模块,哪里需要引入就可以了,所以需要借助@babel/plugin-transform-runtime
十一、处理html资源
解决手动引入打包好的文件如css、js,需要使用html-webpack-plugin,他会生成一个html,并引入我们打包好的js,如果只有一个js我们可以手动加,但是一个项目打包完一般都不会只有一个js,所以我们最好是使用这个插件来动态的插入打包好的文件,官网参照webpack.docschina.org/plugins/htm…
直接new HTMLWebpackPlugin的话他会新建一个html然后引入我们打包之后的文件,所以我们需要加个template参数,其次我们发现打包好的js是放到head中引入的,但是加了defer
new HTMLWebpackPlugin({
template:resolve(__dirname,'public/index.html'),
})
十二、添加dev-server实现自动更新
在开发过程中,如果我们修改了内容就需要去打包的话是很费时的,所以有了热更新;dev-server并没有将我们的代码实时打包到本地,而是打包到内存中,这样我们读取更快,在开启dev-server的时候其实是启动了一个服务器,并且sockjs在浏览器与服务器之间是建立了一个长连接的,以便将webpack编译和打包的各阶段状态告诉浏览器,webpack-dev-server调用webpack api监听了complie的done事件将打包后的hash值传到浏览器进行比较,参照zhuanlan.zhihu.com/p/30669007,官网配置webpack.docschina.org/api/webpack…;开启devserver后启动需要使用npx webpack serve
在配置dev-server的时候有一个属性是hot,是模块热更新,他可以只更新我们修改的文件,而不需要全部的打包,但是他不是配置了就生效的,css样式可以实现热更新是因为使用了style-loader,如果想要js也热更新需要自己写一些代码,或者使用vue-loader或者react-hot-loader
devServer: {
host: 'localhost',
port: 3000,
open: true,
hot:true // 模块热更新,默认值就是true
},
// 如果没有使用vue-loader或者react-hot-loader,可以按照下面的方式写
if(module.hot){
module.hot.accept('xxx.js')
}
十三、区分开发环境和生产环境
开发环境和生产环境还是有很大的不一样的,比如生产环境不需要自动更新、eslint,开发环境不需要压缩、clean等,最重要的是模式配置不一样,所以我们需要区分生产环境和开发环境,建一个config文件夹,里面配置生产环境和开发环境两个js,外面的webpack.config.js就不需要了,因为改了文件位置,所以里面的路径配置需要改一下,相对路径不需要修改,他是根据执行命令的位置去找的,绝对路径就要往上找一层,执行命令npx webpack serve --config ./config/webapck.dev.js
现在输入的命令变长了,我们可以在package.json的scripts中配置短命令,这里就不需要加npx了,运行就使用npm run +短命令
十四、提升开发体验sourceMap
我们使用webpack的话,运行的代码都是进行编译之后的,所以和源代码会存在差异,所以如果代码报错是很难定位的,sourceMap是在编译的时候生成一个.map的文件,用来记录编译之后的代码和源代码的一个映射关系;source map是不影响网页的性能的,因为他只有在打开了开发者工具的情况下才会下载;具体配置项看官网:webpack.docschina.org/configurati…
一般来说都是在source-map前面加上前缀
cheap:不映射列名,但是会告诉在哪行,映射的代码是编译之后的
module:映射的代码是编译之后的,一般和cheap配合使用,就会告诉在几行,会显示源代码
在开发环境一般就使用cheap加上module就可以了即cheap-module-source-map,在生产环境使用source-map即可
十五、提高打包构建速度
在开发模式下前面提到的热更新是可以提高我们的构建速度的
oneOf
我们的loader解析文件的时候,他其实是会遍历rules中所有的loader看是否能够解析我们的文件,就算前已经匹配到了,也会往后再去查找;所以可以配置oneOf,每个文件只被一个loader解析,找到能够解析文件的loader之后就不再往后找了
我的demo的文件很少,js只有两个文件,也是可以看到打包的时间变少了的
exclede/include
排除或者包含某些文件,比如node_modules下的文件我们是不需要再编译了的或者说我们只需要编译src下面的文件,这两个配置只能写一个,一般都是针对js文件做处理,配置babel的时候有写过
cache
缓存打包结果,第二次打包速度就更快了,一般也是针对js,缓存的位置一般是node_modules下面
开启缓存之后效果还是很明显的
开启多进程打包thread-loader
多进程打包一般用于特别耗时的操作中,因为开启一个进程也是需要耗时的大约是600ms,我们启动进程的数量就是我们的CPU核数,所以开启过多的进程是没有用的,官网webpack.docschina.org/loaders/thr…
获取我们电脑的CPU核数,使用node运行一下就可以获得
一般我们的多进程只用于Eslint和Babel以及webpack内置的js压缩插件,如果需要对内置的js压缩插件做处理就需要引入
const os = require('os');
const threads = os.cpus().length;
// webpack内置的js压缩插件,因为需要修改配置所以需要单独引入
const TerserWebpackPlugin = require('terser-webpack-plugin');
{
...
plugins:[
new TerserWebpackPlugin({
parallel:threads
})
]
}
可以看到开启多进程之后打包速度是变慢了的,因为开启进程需要时间,而且我们的js本来就很少,所以时间反倒是变慢了的
十六、代码分割
如果我们项目庞大,将所有的js都打包到一个文件中,那么我们首屏渲染的时候会加载很多其他模块的js,这样首屏渲染就很慢;所以我们可以将代码进行分割,这样我们渲染哪个页面就只加载某个js,代码分割为我们所做的事情就是:1、将打包文件进行分割生成多个打包文件,2、按需加载,需要哪个文件就加载哪个文件
如果是多页应用,我们可以设置多入口就可以实现文件的拆分,只需要将entry改为对象即可
现在我们基本都是单页应用,一般来说只有一个入口文件,那么我们可以通过import动态引入的方式去打包成多个chunk,要想分割代码还需要配置splitChunks,splitChunks里面还有很多配置,还能将公共的代码分割成单独的文件等等,还有一点需要注意就是node_modules里面的文件也会被单独分割
最后:更多配置详情