配置
- entry:配置模块的入口;string?
'./src/index.js'
,单入口,打包生成一个boundle文件;Array?['./src/index.js', './src/add.js']
,多入口,打包还是只能生成一个boundle文件,但是这种方式能解决HMR热更新下HTML页面不能更新的问题,object,{index: ['./src/index.js', './src/count.js'], add: './src/add.js'}
,多入口,可以生成多个boundle文件,本例中是两个。 - output 配置如何输出最终想要的代码,
filename: 'js/[name].js'
,打包之后的文件名称+目录;path: resolve(__dirname, 'build'),
,所有文件资源的输出目录;publicPath: '/'
,所有资源的公共前缀,‘imgs/a.jpg’ --> ‘/imgs/a.jpg’;chunkFilename: 'js/[name]_chunk.js'
,非入口文件的chunk名称(非入口文件包括第三方库文件或者采用import.then的方式);library: '[name]'
,整个库向外暴露的变量名;libraryTarget: 'window'
,整个库向外暴露的变量名添加到window上 - Resolve 自定义路径,
alias: {$css: resolve(__dirname, 'src/css')}
,配置路径别名,在使用中$css就代表src/css;extensions: ['.js', '.json', '.jsx', '.css']
,配置省略文件的后缀名,配置后index.css可以写为index(注意配置后,JS和CSS文件不要重名,否则可能会出错);modules: [resolve(__dirname, '../../node_modules'), 'node_modules']
,告诉webpack解析模块的目录,不配置的话webpack可能会一层一层的找,比较耗时间,第二个元素作用是如果找不到,匹配同级的node_modules - Module 配置如何处理loader模块,
test: /\.css$/
,匹配CSS结尾的文件;exclude: /node_modules/
,不匹配node_modules文件夹下的文件;include: resolve(__dirname, 'src')
,只检查src下的文件;use: ['style-loader', 'css-loader']
,使用多个loader;loader: 'eslint-loader'
,使用单个loader;enforce: 'pre'
,优先匹配这个loader,post是延后匹配这个loader - Plugin 用于扩展 Webpack 功能
- devServer 开启代理服务器,运行webpack代码,它遵守WS协议
模块
- style-loader: 创建Style标签,将JS中的CSS代码放入style标签中
- css-loader:匹配CSS文件,并且将css中的代码转为JS中的CSS代码
- less-loader less:匹配less文件,将less代码转化为css代码
- url-loader:处理图片资源(很小的图片可以base64处理,减轻服务器压力),但是它处理不了html中引入的图片(html中的图片是commjs引入,url-loader是es6模块化解析)
- html-loader:解决url-loader无法处理html中引入图片的问题,但需要在url-loader配置中关闭es6模块化解析
- file-loader:打包其他资源(html/css/js之外的,比如说icon图标,MP3文件等)
- postcss-loader postcss-preset-env :兼容CSS,如果postcss-preset-env插件配置出错,可以使用autoprefixer代替
- eslint-loader eslint:检查自己的源码,不检查第三方库
- eslint-config-airbnb-base eslint-plugin-import:eslint检查规则插件,配合eslint使用
- babel-loader @babel/core @babel/preset-env core-js:按需配置JS兼容性处理,注意不能与@babel/polyfill(全部兼容性处理)混合使用
- @babel/polyfill:全部兼容性处理,但是如果只解决部分兼容性问题,用这个插件打包体积会很大
- thread-loader:多进程打包
插件
- mini-css-extract-plugin:单独生成CSS文件,它可以解决闪屏现象,因为style-loader将JS中的样式代码转为Style标签,这个过程会出现闪屏
- html-webpack-plugin:默认创建一个空的HTML,自动引入打包输出的资源
- optimize-css-assets-webpack-plugin :压缩CSS
- workbox-webpack-plugin:离线可访问插件
- add-asset-html-webpack-plugin:引入之前打包的资源
devServer
- 提供 HTTP 服务而不是使用本地文件预览
- 监听文件的变化并自动刷新网页
- 支持 Source Map
DevServer 会启动一个 HTTP 服务器用于服务网页请求,同时会帮助启动 Webpack ,并接收 Webpack 发出的文件更变信号,通过 WebSocket 协议自动刷新网页做到实时预览。
性能优化
- devServer:当我们在package.json中配置了browserslist(css兼容)选项,并且使用webpack devServer服务器时,会造成页面不能自动刷新的问题
- 解决:添加target:'web’选项
- HMR:热模块替换 / 模块热替换,一个模块发生变化,只会重新打包这一个模块(如果不加HMR功能会打包所有模块,极大降低构建速度)
- 如何添加HMR功能:在devServer中添加hot:true即可,或者命令行中加入 --hot
- 具体分析(JS/CSS/HTML)
- CSS:不必单独配置,因为style-loader内部实现了(这也是为什么开发环境使用style-loader,因为它内部实现了HMR功能,提升构建速度); 为什么生产模式不适用style-loader?因为style-loader会产生白屏问题,效果不好
- JS:默认不能使用HMR功能 --> 需要修改js代码,添加支持HMR功能的代码,注意:HMR功能对JS的处理,只能处理非入口文件
- html:默认不能使用HMR功能,并且使用HMR功能会导致一个问题,html文件不能热更新了;解决:修改entry入口,将html文件引入(其实HTML不用做HMR功能,因为在单页面应用中只有一个HTML页面)
- devtool:一种提供构建后代码到源代码的映射技术(如果构建后代码出错了,可以通过映射追踪到源代码)
- oneOf:假设对于一个CSS文件来说,他被
/\.css$/
正则匹配后,他还会继续执行其他的匹配条件,比如说less-loader的/\.less$/
,babel-loader的/\.js$/
,这样会影响代码的构建速度,所以我们使用oneOf,当一个文件被一个loader的正则表达式匹配后,不继续匹配其他的loader正则表达式(但是这样做不适合一个文件需要多个loader先后匹配,比如说babel-loader和eslint-loader,他们都会匹配JS文件,但是需要先匹配eslint-loader,在匹配babel-loader,所以遇到这种情况,需要把先匹配的loader放到oneOf外面) - babel缓存:如何开启babel缓存?在options选项中加入
cacheDirectory: true
,在第二次构建时,如果代码没有发生变化,则不会产生新的文件;文件资源缓存的区别(hash,chunkhash,contenthash)?当我们把文件名设置为hash时,每次改变文件,重新打包,所有文件hash值都会变化;当我们把文件名设置为chunkhash时,因为css是在index.js中被引入的,改动index.js文件,里面引入的css文件也会被重新打包,chunkhash也会变化,所以chunkhash也不合适;当我们把文件名设置为contenthash时,改变文件,重新打包,文件的contenthash是根据文件的内容进行打包的,如果内容没有变化,contenthash值就不会变,所以contenthash最合适 - tree shaking :去除无用代码,它在生产环境和ES6模块化方式下生效,如果在开发环境,需要我们手动配置,
在webpack.config.js中添加optimization:{usedExports: true}
;使用tree shaking带来的一些问题?对于一些css代码,他并没有被使用,可能导致它意外被tree shaking 掉,对于全部兼容性处理的@babel/poly-fill插件也一样,因为它是全部兼容性处理,可能有的方法没有被使用,所以它也可能被意外tree shaking 掉,要解决这个问题,需要我们在package.json中手动配置"sideEffects":["@babel/polyfill","*.css"]
,他的作用是不对@babel/poly-fill插件和css结尾的文件进行tree shaking - code split:导出多个文件,实现按需加载;对于单页面应用,入口文件只有一个,所以它只会打包生成一个JS文件,配置
optimization{splitChunks:{ chunks: 'all'}}
,可以单独打包node_modules
中的代码;对于多页面应用,可以配置多个入口文件,并且也可配置optimization{splitChunks:{ chunks: 'all'}}
,在多页面应用中,它不仅可以实现单独打包node_modules
,对于同一个node_modules
文件,它只会打包一次;最后,可以通过import(/* webpackChunkName: 'test' */'./test')
的方式,手动配置单独打包的文件 - 懒加载:当文件需要使用时才加载(第二次加载时也是使用的缓存),
import(/* webpackChunkName: 'test', webpackPrefetch: true */'./test').then(({ mul }) => {console.log(mul(4, 5));});
- 预加载:正常加载可以认为是并行加载,预加载是等待其他资源加载完毕(不会阻塞),在偷偷加载预加载的文件
- PWA:离线可访问功能,他需要安装
workbox-webpack-plugin
插件,并且需要兼容性处理,如果配置了eslint,因为浏览器对象navigator对于eslint来说,识别不出来,所以需要在package.json中加入代码,"env": {"browser": true }
让eslint不检查浏览器对象 - 多进程打包:对于一些比较耗时间的loader来说,可以开启多个进程打包处理,比如说babel-loader,可以开启多个线程打包它,缩短打包时间(进程开启大约需要600ms,进程通信也消耗时间,如果代码量少,不建议开启多线程打包)
- externals(ɪkˈstɜːrnlz):拒绝一些插件或者框架参与打包(可提升构建速度),
externals: {// 拒绝jQuery被打包进来jquery: 'jQuery'}
,这里我们拒绝了jqery参与打包,但是我们还想要使用jqery,可以使用cdn的方式引入<script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
- dll:对某些第三方库进行单独打包,在单页面应用中,因为code split 只会打包成一个chunk代码,但是第三方库一般是不需要经常更新的;为了提升构建速度,将多个库打包成多个chunk代码,所以在重新构建时,第三方库不重新打包,为了实现这个功能我们需要创建webpack.dll.js 文件,并且在打包之前要先执行
webpack --config webpack.dll.js
命令,打包第三方库的代码(如果第三方库没有版本更新,执行一次即可),在进行webpack打包,就不会打包第三方库代码了