一、Webpack简介
1、webpack是什么?
Webpack是一种前端资源构建工具,一个静态模块打包器(module bundler)
在 Webpack看来,前端的所有资源文件(js/json/css/img/less/…)都会作为模块处理
它将根据模块的依赖关系进行静态分析,打包生成对应的静态资源(bundle)
2、Webpack的五个核心概念
Entry
入口指示 Webpack以哪个文件为入口七点开始打包,分析构建内部依赖图
Output
输出指示 Webpack打包后的资源bundles输出到哪里去,以及如何命名
Loader
Loader让Webpack 能够去处理那些非JavaScript文件(webpack自身只理解JavaScrpit)
Plugins
插件可以用于执行范围更广的任务.插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量等
Mode
模式指示Webpack使用相应模式的配置
选项 |
描述 |
特点 |
development |
会将process.env.NODE_ENV的值设置为development. 启用NamedChunksPlugin和NamedModulesPlugin |
能让代码本地调试运行的环境 |
production |
启动好多东西…. |
能让代码优化上线运行的环境 |
3、Webpack初体验
Ⅰ、安装与使用
- 先安装全局webpack包(也可以不安装)
1
| npm i webpack webpack-cli -g
|
- 初始化项目npm包(下一步有可能填(webpack_test,然后默认一直回车就行))
安装当前项目webpack包
查询版本号 npx webpack -v
查看 webpck 最新版本 npm info webpack
```
npm i -D webpack webpack-cli //webpack5
npm i -D webpack@4 webpack-cli@3 //webpack4
1 2 3 4
| ```SHELL 最新安装 npm i webpack webpack-cli -D
|
卸载现有的版本
1
| npm uninstall webpack -g
|
版本号必须合理,不然bug会很多
webpack4推荐:
1
| npm i postcss-loader@4.x postcss-preset-env@6.x css-loader@5.x less-loader@7.x less@4.x sass-loader@10.x sass@1.x style-loader@2.x mini-css-extract-plugin@1.x webpack@4.41.6 webpack-cli@3.3.11 -D
|
全局安装webpack,这里安装3.6.0,主要使用vue cli2,-g表示全局安装;
局部安装使用:—save-dev是开发时依赖;
1 2 3
| cd 项目目录
npm i webpack@3.6.0 --save-dev
|
Ⅱ、编译打包应用
创建相关文件夹与文件(build与src文件加与index.js)
运行指令
a)开发环境指令:webpack ./src/index.js -o ./build/built.js --mode=development
webpack就会以./src/index.js
为入口文件开始打包,打包后输出到./build/built.js
整体打包环境,是开发环境
b)生产环境指令:webpack ./src/index.js -o ./build/built.js --mode=production
做的都是一样的,环境是生产环境
c)当配置文件写好后,可以直接使用webpack
指令进行打包
二、Webpack配置详解
1、在学习过程中这部分本是最后学习的,但本人认为可先放前面,先了解后再去使用.
建议:二
—> 三
—> 四
—> 二
顺序翻阅,先粗略过一遍二
,有不懂的留着疑惑看二、三,最后再回头看这里
2、webpack配置实际是创建一个对象,所以里面的属性并没有执行顺序,即使你将entry
写在output
下面都可以执行,因为到时候执行的时候是webpack通过调用对象属性进行实现顺序的
Ⅰ- entry
entry:入口起点
,有三种形式写法
1、string
—> ‘./src/index.js’
单入口:打包形成一个chunk(模块),输出一个bundle(包)文件
此时默认的chunk名称是main
2、array
—> [‘./src/index.js’,’./src/add.js’]
多入口:所有入口文件最终只会形成一个chunk,输出出去只有一个bundle文件(类似将add.js打包进index.js中)
—>通常只有在HMR功能中使用
, 让html热更新生效使用
3、object
—> {index:’./src/index.js’,add:’./src/add.js’}
多入口:有几个入口文件就形成几个chunk,输出几个bundle文件
此时chunk名称是 key
4、特殊用法(混合使用)
通常在dll
优化功能中使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| module.exports = { entry: { index: ['./src/index.js', './src/count.js'], add: './src/add.js' }, output: { filename: '[name].js', path: resolve(__dirname, 'build') }, plugins: [new HtmlWebpackPlugin()], mode: 'development' };
|
Ⅱ- output
使用entry为单入口
为例讲解
1、filename
:文件名称(指定名称+目录)
2、chunkFilename
:非入口chunk的名称,如未指定这项,在入口文件中导入的js打包也会用上filename
的文件名称进行命名,但是名字与入口文件冲突,就会使用0~∞数字命名,不容易区分
3、path
:输出文件目录(将来所有资源输出的公共目录)
4、publicPath
:所有资源引入公共路径的前缀 — ‘img/a.jpg’—>’/img/a.jpg’ 这个适合生产环境使用
这两者变化区别:前者是将imgs
目录跟在当前目录路径后面,后者是将imgs跟在服务器地址后面
5、library:'[name]'
//整个库向外暴露的变量名 实际上使用var声明
6、libraryTarget
:将变量名添加到哪个对象上
a) libraryTarget: ‘window’ 适合浏览器端
b) libraryTarget: ‘global’ 适合node
c) libraryTarget: ‘commonjs’ 使用commonjs方式进行模块导出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = { entry: './src/index.js', output: { filename: 'js/[name].js', path: resolve(__dirname, 'build'), publicPath: '/', chunkFilename: 'js/[name]_chunk.js', }, plugins: [new HtmlWebpackPlugin()], mode: 'development' };
|
Ⅲ- module
1、test
:文件名匹配规则,后面参数是一个正则
2、exclude
:排除匹配某个目录下的内容 —> exclude: /node_modules/ ->排除node_modules下的文件
3、include
:只检查 某个目录下的文件 —> include: resolve(__dirname, ‘src’) ->只检查 src 下的js文件
4、loader
与use
:单个loader使用loader
,多个loader用use
5、enforce
:指定该配置的执行顺序: enforce:’pre
‘(优先执行) > 默认 > enforce:’post
‘(延后执行)
6、options
:指定这个loader的配置选项
7、oneOf: []
:里面的配置只会生效一次,即里面有100个配置,当我一个文件进入这里检测,可能第10个配置匹配到了就生效,然后该文件就不会进行下面90次匹配,如果是不放oneOf
里面的配置,就会完全执行100次匹配,性能优化使用
该部分知识在优化
部分:当你使用enlint与babel两种配置进行对于js文件的匹配的情景下会使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = { entry: './src/index.js', output: { filename: 'js/[name].js', path: resolve(__dirname, 'build') }, module: { rules: [ { test: /\.js$/, exclude: /node_modules/, include: resolve(__dirname, 'src'), loader: 'eslint-loader', enforce: 'pre', options: {} }, { oneOf: [] } ] }, plugins: [new HtmlWebpackPlugin()], mode: 'development' };
|
Ⅳ- resolve
该resolve并不是path
的relove,而是配置中的resolve配置项:解析模块的规则
1、alias
:配置解析模块路径别名: 优点简写路径 缺点路径没有提示
2、extensions
:配置省略文件路径的后缀名
3、modules
:告诉webpack解析模块是去哪个目录 —>如果不指定会webpack会一层一层往外找,造成不必要的性能浪费
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = { entry: './src/js/index.js', output: {}, module: { rules: [ ] }, plugins: [new HtmlWebpackPlugin()], mode: 'development', resolve: { alias: { $css: resolve(__dirname, 'src/css') }, extensions: ['.js', '.json', '.jsx', '.css'], modules: [resolve(__dirname, '../../node_modules'), 'node_modules'] } };
|
配置后js引用示例代码
Ⅴ- devServer
这部分配置很多,只抽出我觉得比较重要的部分
1、proxy
:服务器代理 —>解决开发环境跨域问题
① target: 一旦devserver服务器接收到/接口名/xxx
,就会把请求转发到target
后面的参数url服务器上
② pathRewrite:发送请求时,请求路径重写 —> 如:将/api/xxx ->/xxx(去掉前面的/api)
2、contentBase
:指定运行代码的目录
3、hot
:开启HMR模块热替换
,这是优化部分功能
4、overlay
:当设置为false
时,如果代码错误,不要进行全屏提示
5、watchContentBase
:当设置为true
时,监听contentBase目录下的所有文件 一旦文件变化就会reload
6、watchOptions
:内部设置监听的忽略文件,通常与5
搭配使用
7、compress
:是否开启gzip
压缩
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = { devServer: { contentBase: resolve(__dirname, 'build'), watchContentBase: true, watchOptions: { ignored: /node_modules/ }, compress: true, port: 5000, host: 'localhost', open: true, hot: true, clientLogLevel: 'none', quiet: true, overlay: false, proxy: { '/api': { target: 'http://localhost:3000', pathRewrite: { '^/api': '' } } } } };
|
Ⅵ- optimization
主要用于优化部分的code split
—>代码分割,这个需要先看优化部分的代码分割后再翻阅
1、splitChunks
:开启代码分割
2、runtimeChunk
:将当前模块的记录其他模块的hash单独打包为一个文件 runtime
解决的问题:当你修改a文件后,因为你使用的是contenthash
作为文件名,它根据内容会生成不同的哈希值,所以你a文件文件名将会变化.而如果你在b文件中导入a文件,b文件就会因为a文件的文件名变化导致b文件自己内容也跟着变化(即使你对b文件无任何修改),导致b文件也会重新打包,缓存失效
解决原理:将当前模块的记录其他模块的hash单独打包为一个文件
3、terser-webpack-plugin
:当你的webpack版本在4.26以上,它使用的是terser
的库进行压缩,要使用的时候需要下载依赖
,且如果要优化压缩速度,需要修改里面配置,否则会使用默认配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
| const TerserWebpackPlugin = require('terser-webpack-plugin') module.exports = { entry: './src/js/index.js', output: { filename: 'js/[name].[contenthash:10].js', path: resolve(__dirname, 'build'), chunkFilename: 'js/[name].[contenthash:10]_chunk.js' }, module: { rules: [ { test: /\.css$/, use: ['style-loader', 'css-loader'] } ] }, plugins: [new HtmlWebpackPlugin()], mode: 'production', resolve: { alias: { $css: resolve(__dirname, 'src/css') }, extensions: ['.js', '.json', '.jsx', '.css'], modules: [resolve(__dirname, '../../node_modules'), 'node_modules'] }, optimization: { splitChunks: { chunks: 'all' --------------------------------------------------------------------------- minSize: 30 * 1024, maxSize: 0, minChunks: 1, maxAsyncRequests: 5, maxInitialRequests: 3, automaticNameDelimiter: '~', name: true, cacheGroups: { vendors: { test: /[\\/]node_modules[\\/]/, priority: -10 }, default: { minChunks: 2, priority: -20, reuseExistingChunk: true } -------------------------------------------------------------------------------------------- } }, runtimeChunk: { name: entrypoint => `runtime-${entrypoint.name}` }, minimizer: [ new TerserWebpackPlugin({ cache: true, parallel: true, sourceMap: true }) ] } };
|
三、Webpack.config.js基本配置学习
详细参数部分见下面内容的webpack配置详解
1、module:moudle对应loader(加载器 )的配置,主要对指定类型的文件进行操作
举例
:js类型的文件和css文件需要不同的loader来处理。最常用的加载器是eslint-loader和babel-loader。
2、Plugin: plugins用于扩展webpack的功能,相比着loader更加灵活,不用指定文件类型
举例
:html-webpack-plugin、commonChunkPlugin和ExtractTextPlugin
3、Output: 指定输出编译后代码的位置。
注意
:即使指定了多个入口点(entry points),Ouput配置项也只能设置一个。
4、mode:指定模式:开发模式(development)
和生产模式(production)
注意
:生产模式默认会压缩js文件
5、loader:当引用多个loader时,使用use["loader名1","loader名2"]
形式引入,单个时使用loader:'loader名'
形式
注意:
1、loader
的配置:rules执行顺序是从下往上,从右往左
执行
2、对于rules中的loader,webpack还定义了一个属性 enforce,可取值有 pre
(为pre loader)、post
(为post loader),如果没有值则
为(normal loader)。所以loader在webpack中有4种:normal,inline,pre,post。
1、开发环境配置部分
Ⅰ-通用配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = { entry: './src/index.js', output: { filename: 'built.js', path: resolve(__dirname, 'build') }, module: { rules: [
] }, plugins: [ ], mode: 'development', }
|
Ⅱ-打包样式资源
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| module: { rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] }, { test: /\.less$/, use: [ 'style-loader', 'css-loader', 'less-loader' ] } ] },
|
loader
的配置:rules执行顺序是从下往上,从右往左执行
css
需要下载依赖`npm i style-loader css-loader -D
- 使用
less
的时候需要在上面css依赖基础上再下载npm i less-loader less -D
Ⅲ-打包html
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin');
plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' }) ],
|
plugins打包html需要下载依赖:npm i html-webpack-plugin -D
Ⅳ-打包图片资源
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| module: { rules: [ { test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] }, { test: /\.(jpg|png|gif)$/, loader: 'url-loader', options: { limit: 8 * 1024, esModule: false, name: '[hash:10].[ext]' } }, { test: /\.html$/, loader: 'html-loader' } ] }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' }) ],
|
ps:url-loader file-loade
r与html-loader
都需要下载依赖
问题一:只设置一个test{/\.(jpg|png|gif)$/} ,loader:'url-loader'
,,默认处理不了html中img图片,html中仍然是./src/img.jpg
解: 需要再引入test:{/\.html$/},才可以,但是这时候解析时会出问题:html的图片路径编程
[object Module]`
问题二:html的图片路径变成[object Module]
分析: 因为url-loader默认使用es6模块化解析
,而html-loader引入图片是commonjs
,所以解析时用的es6模块化解析,出现问题
解决:关闭options
中的url-loader的es6模块化,使用commonjs解析 options:{esModule: false}
Ⅴ-打包其他资源
exclude
:指定除此之外的资源
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| module: { rules: [ { test: /\.css$/, use: ['style-loader', 'css-loader'] }, { exclude: /\.(css|js|html|less)$/, loader: 'file-loader', options: { name: '[hash:10].[ext]' } } ] },
|
Ⅵ-热更新 devServer
热更新需要下载依赖 : npm i webpack-dev-server -D
启动devServer指令为:npx webpack-dev-server
只会在内存中编译打包,不会有任何输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = { entry: './src/index.js', output: {}, module: {}, plugins: [ ], mode: 'development',
devServer: { contentBase: resolve(__dirname, 'build'), compress: true, port: 3000, open: true } };
|
Ⅶ-开发环境配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| const { resolve} = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = { entry: './src/js/index.js', output: { filename: 'js/built.js', path: resolve(__dirname, 'build') }, module: { rules: [{ test: /\.less$/, use: [ 'style-loader','css-loader', 'less-loader' ] }, { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] }, { test: /\.(jpg|png|gif)$/, loader: 'url-loader', options: { limit: 8 * 1024, name: '[hash:10].[ext]', esModule: false, outputPath: 'imgs' } }, { test: /\.html$/, loader: 'html-loader', }, { exclude: /\.(html|js|css|less|jpg|png|gif)/, loader: 'file-loader', options: { name: '[hash:10].[ext]', outputPath: 'media' } } ] }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' }) ], mode: 'development', devServer: { contentBase: resolve(__dirname, 'build'), compress: true, port: 3000, open: true }
}
|
2、生产环境配置部分
Ⅰ-提取css成单独文件
1、抽出成css文件: 防止闪屏现象
因为之前是压缩到js中,当页面加载完后用js进行渲染,当性能不够好时可能出现闪屏现象
抽出成css后用link引入,就不会出现这个现象
2、需要下载依赖:npm i mini-css-extract-plugin
3、使用mini-css-extract-plugin
插件,然后用使用这个插件的loader
取代style-loader
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| const HtmlWebpackPlugin = require('html-webpack-plugin'); const {resolve}=require('path');
const MiniCssExtractPlugin=require('mini-css-extract-plugin') module.exports={ entry:'./src/js/index.js', output:{ filename:'js/built.js', path:resolve(__dirname,'build') }, module:{ rules:[{ test:/\.css$/, use:[ MiniCssExtractPlugin.loader, 'css-loader'] }]}, mode:'development', plugins:[ new HtmlWebpackPlugin({ template:'./src/index.html' }), new MiniCssExtractPlugin({ filename:'css/built.css'}) ] }
|
Ⅱ-css兼容性处理
1、需要依赖postcss—>postcss-loader
和 postcss-preset-env
2、需要修改package.json文件
3、需要设置nodejs的环境变量
4、此处有可能出现问题,问题记载于下方问题解决部分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| const HtmlWebpackPlugin = require('html-webpack-plugin') const MiniCssExtractPlugin = require('mini-css-extract-plugin') const { resolve } = require('path')
process.env.NODE_ENV='development' module.exports = { entry: './src/js/index.js', output: { filename: 'js/built.js', path: resolve(__dirname, 'build') }, module: { rules: [{ test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader', { loader: 'postcss-loader', options: { ident: 'postcss', plugins: () => [ require('postcss-preset-env')() ] } } ] }] }, mode: 'development', plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' }), new MiniCssExtractPlugin({ filename: 'css/built.css' }) ] }
|
默认是生产环境
,所以使用开发环境的时候需要设置nodejs环境
1 2 3 4 5 6 7 8 9 10 11 12
| "browserslist": { "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ], "production": [ ">0.2%", "not dead", "not op_mini all" ] },
|
Ⅲ-css压缩
1、压缩通常用的插件plugins
,而兼容性处理之类的都使用loader
来做
2、下载依赖:optimize-css-assets-webpack-plugin
1 2 3 4 5 6
| const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
plugins: [ new OptimizeCssAssetsWebpackPlugin() ]
|
Ⅳ-js代码检查 _eslint
1、语法检查依赖 eslint-loader
和eslint
2、airbnb规则依赖:eslint-config-airbnb-base
和 eslint-plugin-import
3、 注意
:只检查自己写的源代码,第三方的库是不用检查的
4、设置package.json
中eslintConfig
5、当某些地方代码只是测试使用,不想被eslint检测 :下一行eslint所有规则都失效(下一行不进行eslint检查)
使用注释//eslint-disable-next-line
webpack.config.js配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './src/js/index.js', output: { }, module: { rules: [ { test: /\.js$/, exclude: /node_modules/, loader: 'eslint-loader', options: { fix: true } } ] }, plugins: [ ], mode: 'development' };
|
package.json配置
airbnb
是相对热门的模板
1 2 3 4 5 6
| "eslintConfig": { "extends": "airbnb-base", "env": { "browser": true } },
|
当你想在文件中跳过检测
时 :下一行eslint所有规则都失效(下一行不进行eslint检查)
1 2
| console.log(add(2, 5));
|
Ⅴ-js兼容性处理_babel
js兼容性处理的三种方式:
1、基本js兼容性处理 —>@babel/preset-env
问题:只能转换基本语法,比如promise等高级语法不能转换
2、全部js兼容性处理 —>@babel/polyfill
使用: js代码中直接导入:import '@babel/polyfill';
问题: 我只要解决部分的兼容性问题,但是将所有兼容性代码全部引入,体积太大了
3、需要做兼容性处理的就做:按需加载:core-js
————> 最为推荐
依赖四个下载:babel-loader
、 @babel/core
、 @babel/polyfill
、core-js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| const { resolve } = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = { entry: './src/js/index.js', output: { filename: 'js/built.js', path: resolve(__dirname, 'build') }, module:{ rules:[ { test:/\.js$/, exclude:/node_modules/, loader:'babel-loader', options:{ presets:[[ '@babel/preset-env', { useBuiltIns:'usage', corejs:{ version:3 }, targets:{ chrome:'60', firefox:'60', ie:'9', safari:'10', edge:'17' } } ]] } } ] }, plugins:[ new HtmlWebpackPlugin({ template:'./src/index.html' }) ], mode:'development' }
|
Ⅵ-Js与HTML压缩
1、在生产环境下,会自动进行Js代码压缩
2、HTML压缩需要在HtmlWebpackPlugin
插件的配置中编写要求,如下面代码的去除空格与注释
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = { entry: './src/js/index.js', output: { filename: 'js/built.js', path: resolve(__dirname, 'build') }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html', minify:{ collapseWhitespace:true, removeComments:true } }) ], mode: 'production' };
|
Ⅶ-生产环境配置
完整配置文件以及相应注解
注意
:
1、正常来讲,一个文件只能被一个loader处理.但当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序:
* 如:先执行eslint 再执行babel
* -->因为babel会将es6的语法转为低阶语法如(let->var),如果先转babel的话eslint就会报错
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
| const HtmlWebpackPlugin = require('html-webpack-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin') const { resolve } = require('path');
const commonCssLoader = [ MiniCssExtractPlugin.loader, 'css-loader', { loader: 'postcss-loader', options: { ident: 'postcss', plugins: () => [require('postcss-preset-env')] } } ]
module.exports = { entry: './src/js/index.js', output: { filename: 'js/built.js', path: resolve(__dirname, 'built') }, module: { rules: [ { test: /\.css$/, use: [...commonCssLoader] }, { test: /\.less$/, use: [...commonCssLoader, 'less-loader'] },
{ test: /\.js$/, exclude: /node_modules/, enforce: "pre", loader: 'eslint-loader', options: { fix: true } }, { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader', options: { presets: [ [ '@babel/preset-env', { useBuiltIns: 'usage', corejs: { version: 3 }, targets: { chrome: '60', firefox: '60', ie: '9' } } ] ] } }, { test: /\.(jpg|png|gif)$/, loader: 'url-loader', options: { limit: 8 * 1024, name: '[hash:10].[ext]', outputPath: 'imgs', esModule: false } }, { test: /\.html$/, loader: 'html-loader' }, { exclude: /\.(js|css|less|scss|html|jpg|png|gif)$/, loader: 'file-loader', options: { outputPath: 'media', name: '[hash:10].[ext]' } } ] }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html', minify: { collapseWhitespace: true, removeComments: true } }), new MiniCssExtractPlugin({ filename: 'css/built.css' }), new OptimizeCssAssetsWebpackPlugin() ], mode: 'production' }
|
package.json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| { "name": "webpack_code", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "devDependencies": { "@babel/core": "^7.8.4", "@babel/polyfill": "^7.8.3", "@babel/preset-env": "^7.8.4", "add-asset-html-webpack-plugin": "^3.1.3", "babel": "^6.23.0", "babel-loader": "^8.0.6", "core-js": "^3.6.4", "css-loader": "^3.4.2", "eslint": "^6.8.0", "eslint-config-airbnb-base": "^14.0.0", "eslint-loader": "^3.0.3", "eslint-plugin-import": "^2.20.1", "file-loader": "^5.0.2", "html-loader": "^0.5.5", "html-webpack-plugin": "^3.2.0", "less": "^3.11.1", "less-loader": "^5.0.0", "mini-css-extract-plugin": "^0.9.0", "optimize-css-assets-webpack-plugin": "^5.0.3", "postcss-loader": "^3.0.0", "postcss-preset-env": "^6.7.0", "style-loader": "^1.1.3", "terser-webpack-plugin": "^2.3.5", "thread-loader": "^2.1.3", "url-loader": "^3.0.0", "webpack": "^4.46.0", "webpack-cli": "^3.3.12", "webpack-dev-server": "^3.10.3", "workbox-webpack-plugin": "^5.0.0" }, "dependencies": { "jquery": "^3.4.1" }, "browserslist": { "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ], "production": [ ">0.2%", "not dead", "not op_mini all" ] }, "eslintConfig": { "extends": "airbnb-base", "env": { "browser": true } }, "sideEffects": [ "*.css" ] }
|
四、Webpack优化
Ⅰ- HMR优化
HMR
: hot module replacement热模块替换
/模块热替换
作用:一个模块发生变化,指挥重新打包这一个模块(而不是打包所有模块) 极大的提升构建速度,主要是在开发模式中使用
,方便调试
1、样式文件:可以使用HMR功能:因为style-loader
内部实现了
2、js文件:默认不能使用HMR功能
使用方法—>需要修改js代码
,添加支持HMR功能的代码
注意:HMR功能对js的处理,只能处理非入口js文件
的其他文件
3、html文件:默认不能使用HMR功能,同事会导致问题:html文件不能热更新了
解决:修改entry入口
,将html文件引入(不用做HMR功能,毕竟现在流行单页面应用)
基于前面的开发环境配置部分
代码进行优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| const {resolve}=require('path'); const HtmlWebpackPlugin=require('html-webpack-plugin');
module.exports={ entry:['./src/js/index.js','./src/index.html'], output:{ filename:'js/built.js', path:resolve(__dirname,'build') }, module:{ rules:[ { test:/\.less$/, use:['style-loader','css-loader','less-loader'] }, { test:/\.css$/, use:['style-loader','css-loader'] }, { test:/\.(jpg|png|gif)$/, loader:'url-loader', options:{ limit:8*1024, name:'[hash:10].[ext]', esModule:false, outputPath:'imgs' } }, { test:/\.html$/, loader:'html-loader' }, { exclude:/\.(html|js|css|less|jpg|png|gif)$/, loader:'file-loader', options:{ name:'[hash:10].[ext]', outputPath:'media' } } ] }, plugins:[ new HtmlWebpackPlugin({ template:'./src/index.html' }) ], mode:'development', devServer:{ contentBase:resolve(__dirname,'build'), compress:true, port:3000, open:true, hot:true } }
|
js进行HMR优化,在入口文件写下监听代码
注意:你要监听进行热模块替换
,前提是你这个js要在入口文件中导入
,然后入口文件中才能监听得到变化
1 2 3 4 5 6 7 8 9 10
| import print from './print'; import test from './test'; if (module.hot) { module.hot.accept(['./print.js','./test.js'], function() { console.log("前提是你要在入口文件上导入,才能监听得到变化") }); }
|
Ⅱ- source-map 优化
1、source-map
: 一种 提供源代码到构建后代码映射 技术 (如果构建后代码出错了,通过映射可以追踪源代码错误)分为内联
与外部
:
2、内联和外部的区别:1. 外部生成了文件,内联没有 2. 内联构建速度更快
3、不同环境选择:
开发环境
:考虑 速度快,调试更友好
① 速度快(eval>inline>cheap>…): eval-cheap-souce-map > eval-source-map
② 调试更友好: souce-map > cheap-module-souce-map > cheap-souce-map
③ 最优选—> eval-source-map
> eval-cheap-module-souce-map
生产环境
:考虑 源代码要不要隐藏? 调试要不要更友好
① 内联会让代码体积变大,所以在生产环境不用内联
② 考虑隐藏:nosources-source-map 全部隐藏 >hidden-source-map 只隐藏源代码,会提示构建后代码错误信息
③ 综合考虑:source-map or
cheap-module-souce-map
1 2 3 4 5 6 7 8 9 10
| module.exports = { entry: [], output: { }, module: { rules: [] }, plugins: [], mode: 'development', devServer: {}, devtool: 'eval-source-map' };
|
不同映射模式的区别
:感觉记住结论就好了,真的需要的时候再来翻阅
[inline-|hidden-|eval-] [nosources-] [cheap-[module-]]source-map
1、source-map:外部
错误代码准确信息 和 源代码的错误位置
2、inline-source-map:内联
只生成一个内联source-map
错误代码准确信息 和 源代码的错误位置
3、hidden-source-map:外部
错误代码错误原因,但是没有错误位置
不能追踪源代码错误,只能提示到构建后代码的错误位置
4、eval-source-map:内联
每一个文件都生成对应的source-map,都在eval
错误代码准确信息 和 源代码的错误位置
5、nosources-source-map:外部
错误代码准确信息, 但是没有任何源代码信息
6、cheap-source-map:外部
错误代码准确信息 和 源代码的错误位置
只能精确的行
7、cheap-module-source-map:外部
错误代码准确信息 和 源代码的错误位置
module会将loader的source map加入
Ⅲ- oneOf
正常来说,一个文件会被所有的loader过滤处理一遍,如果我有100个loader配置,那么我一个文件就要被100个loader匹配,而使用oneOf
后,而如果放在oneOf
中的loader规则有一个匹配到了,oneOf
中的其他规则就不会再对这文件进行匹配
注意
:oneOf中不能有两个loader规则配置处理同一种文件,否则只能生效一个 例如:对于js进行eslint检测后再进行babel转换
解决:将eslint抽出到外部,然后优先执行,这样在外部检测完后oneOf
内部配置就会再进行检测匹配
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| module.exports = { entry: './src/js/index.js', output: {}, module: { rules: [ { test: /\.js$/, exclude: /node_modules/, enforce: 'pre', loader: 'eslint-loader', }, { oneOf: [ { test: /\.css$/, use: [...commonCssLoader] }, { test: /\.less$/, use: [...commonCssLoader, 'less-loader'] }, { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader', options: { presets: [ [ '@babel/preset-env', { useBuiltIns: 'usage', corejs: {version: 3}, targets: { chrome: '60', firefox: '50' } } ] ] } } ] } ] }, plugins: [], mode: 'production' };
|
Ⅳ-缓存
缓存需要在server环境
中才有效果
1、babel缓存:
在babel
的loader选项部分添加 cacheDirectory: true
—>让第二次打包构建速度更快
2、文件资源缓存:
文件资源当你文件名不变时会默认读取本地缓存,所以当你修改某个文件内容后,并不能实时更新到线上项目中,所以解决方法是在每次webpack构建时生成一个唯一的hash值加在文件名中,每次修改便改动文件名,达到更新效果.而不同的hash也有不同效果,其中需要选用contenthash
① hash:每次webpack构建时会生成一个唯一的hash值
问题:因为js和css同时使用同一个hash值
,如果重新打包,会导致所有缓存失效(即使你只改动了一个文件)
② chunkhash:根据chunk生成的hash值,如果打包来源于同一个chunk,那么hash值就一样
问题:js和css的hash值还是一样, 因为css时在js中被引入的,所以属于同一个chunk
③ contenthash
:根据文件的内容生成hash值,不同的文件hash一定不一样
—>让代码上线运行缓存更好使用(当你线上项目出现紧急BUG时,可以更快的修改)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| const { resolve } = require('path'); module.exports = { entry: './src/js/index.js', output: { filename: 'js/built.[contenthash:10].js', path: resolve(__dirname, 'build') }, module: { rules: [ { oneOf: [ { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader', options: { presets: [ ['@babel/preset-env', { useBuiltIns: 'usage', corejs: { version: 3 }, targets: {chrome: '60',firefox: '50'}} ] ], cacheDirectory: true } }, } ] } ] }, plugins: [ new MiniCssExtractPlugin({ filename: 'css/built.[contenthash:10].css' }), ], mode: 'production', devtool: 'source-map' };
|
server.js代码
1 2 3 4 5 6 7 8 9 10 11 12 13
|
const express = require('express'); const app = express();
app.use(express.static('build', { maxAge: 1000 * 3600 })); app.listen(3000);
|
Ⅴ-tree shaking 树摇
1、tree shaking
:去除无用代码
前提:1. 必须使用ES6模块化 2. 开启production环境 3.webpack4中,对于嵌套的代码,无法去除
作用: 减少代码体积
2、在package.json中配置
“sideEffects”: false 所有代码都没有副作用(都可以进行tree shaking)
问题:可能会把css / @babel/polyfill (副作用)文件干掉
解决:”sideEffects”: [“.css”, “.less”]
1 2 3
| "sideEffects": [ "*.css" ]
|
Ⅵ-code split 代码分割
1、多入口与单入口文件打包 (通常不使用这个方法,一般使用2、3的方法)
① 多入口:有一个入口,最终输出就有一个bundle
② [name]
:取文件名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = { entry: { index: './src/js/index.js', test: './src/js/test.js' }, output: { filename: 'js/[name].[contenthash:10].js', path: resolve(__dirname, 'build') }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html', minify: { collapseWhitespace: true, removeComments: true } }) ], mode: 'production' };
|
2、optimization: {splitChunks: {chunks: 'all'}}
配置
① 可以将node_modules中代码单独打包一个chunk最终输出
② 自动分析多入口chunk中,有没有公共的文件。如果有会打包成单独一个chunk(多入口文件)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = { entry: { index: './src/js/index.js', test: './src/js/test.js' }, output: { filename: 'js/[name].[contenthash:10].js', path: resolve(__dirname, 'build') }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html', minify: { collapseWhitespace: true, removeComments: true } }) ],
optimization: { splitChunks: { chunks: 'all' }, runtimeChunk: { name: entrypoint => `runtime-${entrypoint.name}` }, }, mode: 'production' };
|
3、单入口文件,且想打包特定js文件为单独文件,在2
的配置基础上再写js代码(入口改为单入口)
通过js代码
,让某个文件被单独打包成一个chunk,该代码写在入口js文件中
import动态导入语法
:能将某个文件单独打包
通过注释
,可以让js生成的打包文件带上这个名字,
在`webpack5`中的`开发模式中可以不用注释加名字`,内部有 chunk 命名规则,不再是以 id(0, 1, 2)命名了,当然生产模式还是有必要的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import('./test') .then(({ mul, count }) => { console.log(mul(2, 5)); }) .catch(() => { console.log('文件加载失败~'); });
console.log(sum(1, 2, 3, 4));
|
Ⅶ- 懒加载 (lazy loading) 和预加载
应用场景:当我们模块很多时,导入的js太多,或者说有的js只有使用的时候才有用,而我一开始便加载,就可能造成一些不必要的性能浪费
1、懒加载:当文件需要使用时才加载
可能的问题
:当用户第一次使用时,如果js文件过大,可能造成加载时间过长(有延迟),但是第二次就不会了,因为懒加载第二次是从缓存中读取文件
2、预加载 prefetch:等其他资源加载完毕,浏览器空闲了,再偷偷加载
正常加载可以认为时并行加载(同一时间加载多个文件,但是同一时间有上限)
就例如下面例子,有预加载的代码运行效果,是页面刷新后,但是还未进行使用时,该文件其实已经加载好了
注意
:预加载虽然性能很不错,但是需要浏览器版本较高,兼容性较差,慎用预加载
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| console.log('index.js文件被加载了~');
document.getElementById('btn').onclick = function() { import('./test').then(({ mul }) => { console.log(mul(4, 5)); }); };
import('./test').then(({ mul }) => { console.log(mul(4, 5)); });
|
Ⅷ- PWA (离线访问)
PWA: 渐进式网络开发应用程序(离线可访问) workbox —>下载依赖: workbox-webpack-plugin
1、在配置中使用该插件 :① 帮助serviceworker快速启动 ② 删除旧的 serviceworker
2、在入口文件js中添加代码
3、eslint不认识 window、navigator全局变量
解决:需要修改package.json中eslintConfig配置
4、代码必须运行在服务器上才有效果
① node.js
② npm i serve -g
—>serve -s build
启动服务器,将build目录下所有资源作为静态资源暴露出去
webpack.config.js新增配置
1 2 3 4 5 6 7 8 9 10
| const WorkboxWebpackPlugin = require('workbox-webpack-plugin'); plugins: [ new WorkboxWebpackPlugin.GenerateSW({ clientsClaim: true, skipWaiting: true }) ],
|
入口文件js —>index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker .register('/service-worker.js') .then(() => { console.log('sw注册成功了~'); }) .catch(() => { console.log('sw注册失败了~'); }); }); }
|
package.json新增配置
1 2 3 4 5 6
| "eslintConfig": { "extends": "airbnb-base", "env": { "browser": true } },
|
Ⅸ-多线程打包
1、下载thread-loader
依赖
2、使用loader: 'thread-loader'
开启多线程打包
注意点:进程启动大约为600ms,进程通信也有开销,只有工作消耗时间较长,才需要多进程打包 比如:babel
转换可以使用多线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| const { resolve } = require('path'); module.exports = { module: { rules: [ oneOf: [ { test: /\.js$/, exclude: /node_modules/, use: [
{ loader: 'thread-loader', options: { workers: 2 } }, { loader: 'babel-loader', options: { presets: [ [ '@babel/preset-env', { useBuiltIns: 'usage', corejs: { version: 3 }, targets: { chrome: '60', firefox: '50' } } ] ], cacheDirectory: true } } ] } ] } ] } };
|
Ⅹ-externals
当你使用外部引入代码时:如CDN引入
,不想他将我引入的模块也打包,就需要添加这个配置
即:声明哪些库是不进行打包的
—>externals
: {}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = { entry: './src/js/index.js', output: { filename: 'js/built.js', path: resolve(__dirname, 'build') }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' }) ], mode: 'production', externals: { jquery: 'jQuery' } };
|
Ⅺ-dll
使用dll技术,对某些库(第三方库
:jquery、react、vue…)进行单独打包
作用:如果不是cdn引入,而是使用第三方库,想要打包后暴露出去,使用该方法
1、首先你需要写一个新的配置文件,因为使用dll
技术,所以命名为webpack.dll.js
当你运行 webpack 时,默认查找 webpack.config.js 配置文件 需求:需要先运行 webpack.dll.js
文件
—>webpack --config webpack.dll.js
在这个文件中进行对某些库的单独打包
2、在webpack.config.js中,需要告诉webpack哪些库不需要再次打包(即在dll.js中打包后生成的文件)
3、这里需要使用到add-asset-html-webpack-plugin
与webpack
插件
4、运行webpack.dll.js
对第三方库进行单独打包后,除非你要加新的库,不然不用再重新打包这个,直接webpack
打包其他的即可
webpack.dll.js配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| const { resolve } = require('path'); const webpack = require('webpack');
module.exports = { entry: { jquery: ['jquery'], }, output: { filename: '[name].js', path: resolve(__dirname, 'dll'), library: '[name]_[hash]' }, plugins: [ new webpack.DllPlugin({ name: '[name]_[hash]', path: resolve(__dirname, 'dll/manifest.json') }) ], mode: 'production' };
|
webpack.config.js配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const webpack = require('webpack'); const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
module.exports = { entry: './src/index.js', output: { filename: 'built.js', path: resolve(__dirname, 'build') }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' }), new webpack.DllReferencePlugin({ manifest: resolve(__dirname, 'dll/manifest.json') }), new AddAssetHtmlWebpackPlugin({ filepath: resolve(__dirname, 'dll/jquery.js') }) ], mode: 'production' };
|
XII-性能优化总结
1、# webpack性能优化
① 开发环境性能优化
② 生产环境性能优化
2、# 开发环境性能优化
① 优化打包构建速度:HMR
② 优化代码调试:source-map
3、# 生产环境性能优化
① 优化打包构建速度
Ⅰ- oneOf
Ⅱ- babel缓存
Ⅲ- 多进程打包
Ⅳ- externals
Ⅴ- dll 这个技术加上代码拆分code split可以做出更加细度化拆分
② 优化代码运行的性能
Ⅰ- 缓存(hash-chunkhash-contenthash)
Ⅱ- tree shaking
Ⅲ-code split
Ⅳ- 懒加载/预加载
Ⅴ- pwa
五、Webpack5的介绍与预学习
此版本重点关注以下内容:
- 通过持久缓存提高构建性能.
- 使用更好的算法和默认值来改善长期缓存.
- 通过更好的树摇和代码生成来改善捆绑包大小.
- 清除处于怪异状态的内部结构,同时在 v4 中实现功能而不引入任何重大更改.
- 通过引入重大更改来为将来的功能做准备,以使我们能够尽可能长时间地使用 v5.
Ⅰ-下载
npm i webpack@next webpack-cli -D
Ⅱ-自动删除 Node.js Polyfills
早期,webpack 的目标是允许在浏览器中运行大多数 node.js 模块,但是模块格局发生了变化,许多模块用途现在主要是为前端目的而编写的。webpack <= 4 附带了许多 node.js 核心模块的 polyfill,一旦模块使用任何核心模块(即 crypto 模块),这些模块就会自动应用。
尽管这使使用为 node.js 编写的模块变得容易,但它会将这些巨大的 polyfill 添加到包中。在许多情况下,这些 polyfill 是不必要的。
webpack 5 会自动停止填充这些核心模块,并专注于与前端兼容的模块。
迁移:
- 尽可能尝试使用与前端兼容的模块。
- 可以为 node.js 核心模块手动添加一个 polyfill。错误消息将提示如何实现该目标。
Ⅲ-Chunk 和模块 ID
添加了用于长期缓存的新算法。在生产模式下默认情况下启用这些功能。
1
| chunkIds: "deterministic", moduleIds: "deterministic"
|
Ⅳ-Chunk ID
你可以不用使用 import(/* webpackChunkName: "name" */ "module")
在开发环境来为 chunk 命名,生产环境还是有必要的
webpack 内部有 chunk 命名规则,不再是以 id(0, 1, 2)命名了
这部分在import动态导入语法
中会用到,如代码分割与懒加载
Ⅴ-Tree Shaking 树摇优化
1、webpack 现在能够处理对嵌套模块
的 tree shaking
在生产环境中, inner 模块暴露的 b
会被删除,原本的webpack4无法判断中间这个被引用的内容是否有所被引用,无法删除
1 2 3 4 5 6 7 8 9 10 11
| export const a = 1; export const b = 2;
import * as inner from './inner'; export { inner };
import * as module from './module'; console.log(module.inner.a);
|
2、webpack 现在能够判断多个模块之前的关系
1 2 3 4 5 6 7 8 9
| import { something } from './something';
function usingSomething() { return something; }
export function test() { return usingSomething(); }
|
当设置了"sideEffects": false
时,一旦发现test
方法没有使用,不但删除test
,还会删除"./something"
3、webpack 现在能处理对 Commonjs 的 tree shaking
Ⅵ-Output
webpack 4 默认只能输出 ES5 代码
webpack 5 开始新增一个属性 output.ecmaVersion, 可以生成 ES5 和 ES6 / ES2015 代码.
如:output.ecmaVersion: 2015
Ⅶ-SplitChunk
之前webpack4只能指定最小文件大小,现在能对不同文件进行最小大小判断
此属性在代码分割的optimization
配置中
1 2 3 4 5 6 7
| minSize: 30000;
minSize: { javascript: 30000, style: 50000, }
|
Ⅷ-Caching
1 2 3 4 5 6 7 8 9
| cache: { type: "filesystem", buildDependencies: { config: [__filename] } }
|
缓存将存储到 node_modules/.cache/webpack
Ⅸ-监视输出文件
之前 webpack 总是在第一次构建时输出全部文件,但是监视重新构建时会只更新修改的文件。
此次更新在第一次构建时会找到输出文件看是否有变化,从而决定要不要输出全部文件。
Ⅹ-默认值
webpack5将部分配置赋予默认值,当你使用如下配置,在webpack5中可以不进行代码编写
entry: "./src/index.js
output.path: path.resolve(__dirname, "dist")
output.filename: "[name].js"
更多内容
###、出现的问题与解决
Ⅰ-如果开启了 eslint 再进行懒加载会报错 无法再非顶层使用import
解决:
1、新建 .eslintrc 文件
2、配置
1 2 3 4 5 6 7
| >{ >"parser": "babel-eslint", >"parserOptions": { "sourceType": "module", "allowImportExportEverywhere": true >} >}
|
Ⅱ-css兼容性配置没效果
可能是版本问题,换个写法
试试
问题代码
1 2 3 4 5 6 7 8 9 10 11
| use: [MiniCssExtractPlugin.loader, 'css-loader', { loader: 'postcss-loader', options: { ident: 'postcss', plugins: () => [ require('postcss-preset-env')() ] } } ]
|
解决代码
如果{}不需要继续传入options,可以直接这样plugins: ['postcss-preset-env']
效果同上
1 2 3 4 5 6 7 8
| { loader: 'postcss-loader', options: { postcssOptions: { plugins: [['postcss-preset-env', {}]] } } }
|