为什么要去学习webpack
开发时可能会使用框架(react、vue)、ES6、less/sass等css预处理器;
这样的代码想要在浏览器运行必须经过编译,成为浏览器可以识别的js、css等语法,才可以运行;
webpack用来处理以上编译,并且具备压缩代码、兼容性处理、提升代码性能;
以一个文件或者多个文件作为打包入口,将整个项目所有文件编译组合成一个或多个文件输出;输出的文件就是编译好的文件,可以在浏览器运行;
webpack输出的文件叫做bundle;
功能介绍
- 开发模式:仅编译js的es module语法;
- 生产模式:能编译js的es module语法,还可以压缩js代码
但是webpack只能处理js语法,遇到css资源就无法处理了
核心功能
- entry
- output
- loader:threader-loader(开启多进程)
- plugin:
- ESLintPlugin
- HtmlWebpackPlugin(创建html文件,结构和原来一致)
- MiniCssExtraPlugin(生成单独的css文件,通过link方式引入)
- CssMinimizerPlugin(压缩css文件)
- TerserWebpackPlugin(js压缩插件,配置项里开启多进程)
- image-minimizer-webpack-plugin(压缩image、有分无损压缩和有损压缩)
- preload:告诉浏览器立即加载资源(只加载,不执行;只能加载当前页面用到的资源)
<Link href="staic/js/math.chunk.js" rel="preload" as="script" />
- prefetch:告诉浏览器空闲时加载资源(只加载不执行;可以加载下一个页面用到的资源)查看兼容性的网站 can I use
- mode
压缩的话,也可以放在optimization里面的minimizer(防止css压缩、js压缩插件)
css处理
动态创建一个style标签,里面是css代码
图片资源
file-loader、url-loader(已经内置,不需要再安装了)
base64:将图片转化为字符串(不需要额外发请求了)
ESLint
eslintrc.js(error、warn)
eslintignore
babel
babel.config.js
presets:[@babel/preset-env, @babel/preset-react, @babel/preset-typescript]
@babel/preset-env:处理箭头函数
在webpack.config.js文件中对js文件加上babel-loader;排除exclude: /node_modules/
处理html资源
htmlPlugin
搭建开发服务器
使用devServer(不会输出资源,是在内存中编译打包);自动搭建服务器,每次有代码修改,都自动重新打包
提取css成单独文件
MiniCssExtraPlugin.loader 替换掉style-loader
样式文件通过link引入,不再通过style标签引入
postcss-loader:处理样式兼容性(比如flex)
CssMinimizerPlugin:css插件压缩css文件
默认html、js都进行了压缩
oneOf
正常来说module加载器里面会设置一个rules规则,匹配对应的文件,匹配到就使用对应的loader来进行配置处理
如果不做任何操作,会给每个文件匹配所有的规则,使用oneOf可以在文件匹配到之后不再往下匹配;
Include/Exclude
开发时需要使用第三方库或者插件,所有文件都会下载到node_modules,这些文件不需要编译可以直接使用,所以处理js文件时,要排除node_modules下面的文件;
include:包含,只处理xxx文件;
exclude:排除,除了xxx文件以外其他文件都处理
include和exclude只能使用一个
使用babel-loader、eslint插件的都需要使用这个
使用babel-loader的使用include,只处理src下面的文件;
使用ESLintPlugin排除node_modules下面的文件;
Cache
每次打包js文件都要经过eslint检查和babel编译,速度比较慢;
可以缓存之前的eslint检查和babel编译结果,这样第二次打包速度就会更快了;
在babel-loader配置项中:添加options配置项;
cacheDirectory: true,// 开启babel缓存
cacheCompression: false,// 关闭缓存文件压缩
提升打包速度
js文件处理主要用了eslint、babel、terser;默认js文件会压缩就是用了terser这个工具;
开启多进程同时处理js文件,速度就比之前的单进程打包更快;
进程启动需要600ms左右时间,所以仅在特别耗时的操作中使用;
使用os库,获取cpus核数;下载thread-loader库;
use: [{loader: 'threader-loader', // 开启多进程处理options: {works: os.cpus().length, // 获取cpus核数}},{loader: 'babel-loader',options: {cacheDirectory: true, // 开启babel缓存}}
]
tree shaking
移除js中没有使用到的代码,依赖于es module
减少babel生成文件体积
babel默认会为每个文件注入辅助代码,使用@babel、plugin-transform-runtime,可以使所有辅助代码从这里引用
优化代码运行
打包代码会将所有js文件打包到一个文件中,体积太大了;只需要渲染首页的话,只加载首页的js文件,其他文件不应该加载;
所以需要用到代码分割;
代码分割:
- 分割文件;
- 按需加载;
分割文件需要用到多入口
module.exports = {entry: {app: './src/app.js',main: './src/main.js',},output: {path: path.resolve(__dirname, 'dist'),filename: '[name].js', // webpack命名方式},plugins: [new HtmlWebpackPlugin({template: path.resolve(__dirname, 'public/index.html'),})]
}
使用splitChunks
动态导入
动态导入的文件会被拆分成一个单独的模块
umi就是利用了这样的特性,会将每一个path对应的文件单独打包
默认配置:
React.lazy(() => import(
/* webpackChunkName: "p__index" */'@/pages/index.tsx')
)