webpack基础
源 - webpack - bundle
1、核心概念
1.1、Entry:指示 webpack 以哪个文件为入口起点开始打包,分析构建内部依赖图
1.2、Output:指示 webpack 打包后的资源 bundles 输出到哪里去,以及如何命名
1.3、Loader:让 webpack 能够去处理那些非JavaScript文件 (webpack 自身只理解JavaScript)
1.4、Plugins:用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量等
1.5、Mode:development、production
2、webpack能处理js/json资源,不能处理css/img等其他资源,也不能将es6语法转成es5以下
3、loader:style-loader、css-loader、less-loader、url-loader(在webpack5中官方文档已经改成asset)、html-loader等
use: [ //use数组是倒序加载,所以先写style添加,再写css //创建style标签,将js中样式资源插入,添加到head 'style-loader', //将css文件以字符串编程commonjs模块加载到js中, 'css-loader' ]
如果需要不同的loader需要加载不同的规则,匹配不同的文件
若background使用图片,可以用url-loader,对图片base64处理,减小服务器压力,但是图片体积会更大,导致文件请求速度更慢,所以一般对小图片处理,10kb左右
4、plugins:HtmlWebPlugin:生成一个 HTML5 文件, 在 body 中使用script标签引入你所有 webpack 生成的 bundle
5、devServer实现热更新,只会在内存编译,不会有任何输出
6、生产环境配置:
6.1:将css文件单独提取:minicss-extract-plugin
6.2:兼容性处理:postcss-loader、post-preset-env,比如内部的browserslist自适应配置浏览器,注意,默认环境变量为生产模式,若为开发模式,需要手动改变NODE_ENV
6.3:压缩css:css-minimizer-webpack-plugin
6.4:js语法检查:eslint-loader、eslint;为了不检查第三方库js,只检查自己的,还需要exclude:/modules/;还需要在package.json添加检查eslintConfig规则:airbnb
6.5:基本js兼容性问题(ES6):babel-loader、@babel/preset-env、@babel/core
6.6:全部js兼容(promise等):@babel/polyfill
6.7:部分兼容性问题(减小体积):core-js
6.8:JS压缩:生产环境UglifyJsPlugin自动压缩
6.9:HTML压缩:HtmlWebpackPlugin:minify:collapseWhitespace:true,removeComments:true
6.10:复用loader:将重复使用的loader放在数组内,引用是运用rest扩展 ...
6.11:当一种文件被多个loader执行的时候,需要指定顺序,如先执行eslint,再到babel。enforce:‘pre’,优先执行
6.12:webpack4:html-loader、url-loader使用的是es6module,要统一配置:在html-loader下配置esModule:false
7、性能优化配置:
7.1:开发环境性能优化:打包构建速度优化、代码调试优化
7.1.1:HMR模块热替换(hot module replacement),devServer内打开hot:true(webpack5默认打开)。单独打包热更新,而不是全部重新打包(样式文件可以、js默认不可以,可以在js内添加hot监听js变化、html默认不可以,但是可以改版entry入口实现)
7.1.2:source-map:源代码转构建代码的映射信息。如果构建后代码错误,可以通过映射信息找到源代码修改。该为基础命令,生成在外部 .map
还有如:inline-source-map在js内内联生成map,统一放在js最后、hidden-source-map外部生成,只有构建后代码错误位置,隐藏源代码、eval-source-map每个文件生成内联sourcemapurl,都在eval函数中、nosource-source-map有错误信息,没有位置,隐藏源代码、cheap-[module]-source-map等配置
开发环境(速度要快(eval>inline>cheap...)eval-cheap-source-map,调试要友好(source-map>cheap-module-source-map))一般用eval-source-map和eval-cheap-module-source-map;
生产环境(源代码是否需要隐藏(nosource-source-map和hidden-source-map),调试是否需要友好)内联让体积变大,一般不用,主要用source-map和cheap-module-source-map;
7.2:生产环境优化:打包构建速度优化、代码运行性能优化
7.2.1:oneOf:每个文件只对应一个loader,不用多次重复扫描匹配loader,但是要注意,同一个文件不能有两个不同rule,不同loader,如js不能即eslint,又babel,把其中一个提出去,也需要注意先后顺序,是否先oneOf内。
7.2.2:缓存优化:生产环境没有HMR,要实现热更新需要开启babel缓存。
又由于缓存的原因,若修复bug或改变样式后,无法重新加载新内容,而是浏览器直接读取缓存旧数据,
所以可以在更新的内容文件名加上hash(hash:10十位哈希),让浏览器重新加载。
但是又有新问题,如果都用hash的话,一个css改动,同hash的js也会重新缓冲,会造成资源浪费
引入chunkhash:根据chunk生成hash,若打包来自同一chunk,则hash相同
但还是有问题,css是通过import到js,若改css,则js也改变,所以他们都属于同一个chunk,hash依旧相同
使用contenthash:根据内容生成不同hash
7.2.3:tree shaking:去除不使用的代码(只引入所需代码)。前提:使用es6模块化,开启production就会默认开启。若配合package.json中"sideEffects":false(即所有代码都可以tree shaking),css会除去。可以写成"sideEffects": ["*.css"]
7.2.4:代码分包/分割code split:
7.2.4.1、单入口,单页面 / 多入口文件,多页面,但是页面越多,越不好改,不好添加
7.2.4.2、splitChunks:根据条件自动拆分chunks:optimization下,如在node_modules中、新chunk大于20kb、多入口文件有没有公共chunk等
7.2.4.3、开发中,单入口会比较多。可以在 js 中动态导入,让某个别的 js 文件单独打包成chunk
7.2.5:懒加载(js懒加载,不是图片):达到某些条件再加载,前提条件就是上述第三种类型的代码分割,其实也是动态导入,比如点击一个按钮后在import
预加载prefetch 提前加载文件,相比于正常加载(并行加载同一文件),预加载等其他资源加载完了,预加载的大文件再加载,让其他资源先加载
7.2.6:PWA(Progressive Web App渐进式网络开发应用程序)离线访问上一次已经加载好的内容。用得不多了。。
7.2.7:多进程打包:优化打包速度。thread-loader,一般给babel用。因为每个 worker 都是一个独立的 node.js 进程,其开销大约为 600ms 左右。同时会限制跨进程的数据交换,只在耗时的操作中使用此 loader,所以一般放在js打包中,且为大js
7.2.8:externals:防止将某些 import 的包(package)打包到 bundle 中,而是在运行时(runtime)再去从外部获取这些扩展依赖,如cdn的jquery
7.2.9:dll(动态链接库):将不同的库打包成不同的chunk,不必像node_modules里全部打包成一个。由于新建了webpack.dll.js包含DllPlugin,但是打包的时候默认运行webpack.config.js,需要修改打包配置为webpack.dll.js(webapck --config webpack.dll.js)生成库。生成完成之后再用webpack.config.js内的DllReferencePlugin,告诉其不需要打包该库,引用(add-asset-html-webpack-plugin)即可
8、详细配置
8.1:entry:入口起点
8.1.1. 当入口为string --> './src/index.js',单入口,打包形成一个chunk,输出一个bundle文件。此时chunk的名称默认是main
8.1.2. 当入口为array -->[ './src/index.js', './src/add.js']。多入口,最后只生成一个chunk,输出一个bundle。主要为HMR服务,让html热更新生效
8.1.3. 当入口为object -->{index: './src/index.js', add: './src/add.js'} key: value。多入口,有几个入口则生成几个chunk与对应的多个bundle,默认名称为key
以上可以结合使用,利于整合
8.2:output:输出
output: { //文件名称(指定名称+目录) filename: 'js/built[name].js', //输出文件目录,所有资源的公共目录 path: path.resolve(__dirname, 'build'), //所有资源的公共路径前缀,生产环境中服务器寻找可能需要前缀/,并不是本地路径 // publicPath:'/', //非入口chunk名称,如import、optimization chunkFilename: 'js/[name]_chunk.js', //全局暴露 library:'[name]', //变量名添加到哪个上,如browser,node等 libraryTarget:'window', clean:true },
8.3:module:
module: { rules: [{ test: /\.css$/, //多个loader use: ['style-loader', 'css-loader'] },{ test: /\.js$/, //不检查 exclude: /node_modules/, //只检查 include:path.resolve(__dirname,'src'), //优先执行 enforce:'pre', //延迟执行 enforce:'post', //若不写,则中间执行 //单个loader loader:'eslint-loader', },{ //配置只生效一个 oneOf:[] }] },
8.4:resolve:解析模块规则
resolve:{ //配置解析路径别名 alias:{ //css绝对路劲,方便查找,import的时候写$即可 $css:path.resolve(__dirname,'src/css'), }, //配置省略路径的后缀名,按顺序查找 extensions:['.js','.json','.css'], //告诉webpack解析模块去哪找,省去一层层查找 modules:[path.resolve(__dirname,'../../node_modules')] }
8.5:devServer:开发环境内调试
devServer: { //代码目录 static: { directory: path.join(__dirname, 'public'), }, //启动gzip压缩,让服务器启动更快 compress: true, port: 9000, host: 'localhost', //自动打开浏览器 open: true, //开启HMR hot: true, //简介启动信息 quiet: true, //出错全屏提示 overlay: true, //服务器代理,解决跨域 proxy:{ //请求转发 '/api':{ target:'http://localhost:3000', //发送请求路径重写,将/api/xxx转成/xxx,即去掉api pathRewrite:{ '^/api':'' } } } },
8.6:optimization:
optimization: { splitChunks: { chunks: 'all', //以下为默认值 //分割的chunk最小为30kb minSize: 30 * 1024, //最大无限制 maxSize: 0, //要提取的chunk最少被引用一次 minChunks: 1, //按需加载时并行加载的文件最大数量 maxAsyncRequests: 5, //入口js文件最大并行请求数量 maxInitialRequests: 3, //名称连接符号 automaticNameDelimiter: '~', //可以使用命名规则 name: true, //分割chunk组 cacheGroups: { //node_modules文件打包到vendors组的chunk中,vendors~xxx.js //这里的打包满足上面的规则 vendors: { test: /[\\/]node_modules[\\/]/, //打包优先级-10 proprity: -10 }, //多入口同一依赖 default: { //要提取的chunk最少引用2次 minChunks: 2, //打包优先级-20 proprity: -20, //如果当前要打包的模块和之前已经提取的是同一个,就会直接复用,不重新打包 reuseExistingChunk: true } } }, //将当前模块记录其他模块的hash单独打包为一个文件,该文件叫runtime //就是生成了一个中间件记录hash保证contenthash不全更新,不影响其他文件缓存 runtimeChunk: { name: entrypoint => `runtime-${entrypoint.name}` }, //配置生产环境压缩方案:js和css minimizer: [ new TerserPlugin({ //开启缓存 cache: true, //启动sourceMap sourceMap: true, //webpack5上面两个不用写 //开启多进程打包 parallel: true, }), ], },
webpack5:

浙公网安备 33010602011771号