快速过一遍Webpack4核心知识

1、webpack和webpack-dev-server区别
webpack 每次会生成一个bundle.js文件,webpack-dev-server不会,只是将打包结果放在内存中,并不会写入实际的bundle.js,在每次webpack-dev-server接收到请求时,都将内存中的打包结果返回给浏览器。

2、webpack-cli安装后可以直接在控制台调用webpack命令
3、url-loader 和 file-loader
url-loader和file-loader都可以用来作为打包图片的loader

url-loader不会生成一个具体的图片文件,而是直接在需要这个图片src地址的地方给出图片的base64地址,这样比较适合几k大小的小图,减少http请求;url-loader有个limit设置一个numer,单位是bytes,如果图片大于这个limit值,则默认使用file-loader, 如果小于则使用url-loader
file-loader会生成一个图片文件,适合大点的图片
4、style-loader作用主要是将css放到dom中
官方英文解释很到位:Adds CSS to the DOM by injecting a

如果配置style-loader/url,则会生成一个类似这样的内联css。

5、postcss-loader与Autoprefixer一起,用来适配各大浏览器厂商css前缀
需要配置postcss.config.js,和安装autoprefixer
6、resolve配置
resolve.alias 设置别名来替换某个路径,如:
resolve:{
alias:{
@: ‘./src/components/’
}
}
当需要引入import './src/components/header’时,可以写成import ‘@/header’

resolve.extensions 设置引入文件的扩展格式,当引入文件省略了后缀名时候,会按照设置的resolve.extensions去相应路径匹配对应格式的文件,默认是[‘js’, ‘json’],如果是react项目可以设置:extensions: [’.jsx’, ‘.js’, ‘.json’]
7、模块样化处理
{
loader: ‘css-loader’,
options: {
importLoaders: 2,
modules: true,
},
},
如上在配置css-loader时候,配置modules: true

但一般出路antd的样式时候,需要做两手处理:

{
test: /.lessKaTeX parse error: Undefined control sequence: \/ at position 30: …: /node_modules\̲/̲antd/, use:…/,
exclude: /node_modules/antd/,
use: [
‘style-loader’,
{ loader: ‘css-loader’, options: {modules: true} },
‘less-loader’
]
}
这样避免了 css-modules 对 antd 的样式进行处理,否则会造成antd 的样式的不匹配。

8、iconfont字体打包
{
test: /.(eot|ttf|svg|woff)$/,
use: {
loader: ‘file-loader’,
},
}
如上示例,打包.eot, .ttf等字体文件

9、html-webpack-plugin
会在打包完成后,自动生成一个html文件,并把打包生成的js自动引入到这个html中
如果希望打包出来的html是按照要求配置的,如加上

,那么就可以在HtmlWebpackPlugin配置中加入template指定一个模板文件
10、clean-webpack-plugin
清除打包数据
clean-webpack-plugin v3.0以上版本,不需要添加额外配置项,默认清除的文件是output.path指定的路径文件夹内容
11、output.publicPath
在output中配置publicPath,如一个路径或者一个cdn地址,然后打包出来的资源会自动加上这个publicPath前缀,如加上一个cdn的host后,打包出来的script的src会在文件名前加上这个cdn地址。
12、source-map
souce-map是源代码和打包后的代码的一个映射关系,对应的webpack配置是devtool,可以快速定位错误行代码。
devtool在mode=development中一般配置,devtool:cheap-module-eval-source-map,这样既可以定位错误正确的位置,同时打包速度也不会太受影响。
devtool在mode=production中一般配置,devtool:cheap-module-source-map。
devtool设置了source-map会生成一个.map映射文件;
设置了带inline,则会将映射文件内容放到打包文件里,不会单独生成.map映射文件;
设置了带cheap的配置只会提示行不提示列错误,同时只提示业务代码,不管loader的打包代码;
设置了带module的是除了核心业务代码,loader打包文件代码也会提示错误位置
设置了带eval的会提高打包速度。
13、devServer
主要用于快速开发应用,提高开发效率
通过设置package.json中的stripts,“watch”: “webpack --watch”,可以实现修改页面代码后自动打包,但是没法开启一个服务,这就不能满足ajax(ajax必须在一个http服务里才能使用)调用服务等开发需求了,此时需要webpack-dev-server了
webpack-dev-server打包出来的文件不会放到原先的dist或者配置好的output路径,而是放到了本地电脑内存中,这样提升打包速度
配置contentBase,告诉服务器从哪个目录中提供内容,填写output的path就可以了
配置open,设为true时devserver启动后自动打开浏览器
配置port,可以修改开启服务的端口号
配置proxy,如果现在在http://localhost:3000上有服务端的话,可以设置proxy: {’/api’: ‘http://localhost:3000’},这样在本地的非3000端口host上请求/api/info接口,实际是请求了http://localhost:3000/api/info,否则会报跨域错误
如果不用 webpack-dev-server,可以通过 webpack-dev-middleware 和express/koa2写一个server.js的服务,然后启动这个服务,可以达到和 webpack-dev-server 一样的修改后自动更新等效果
14、hot-module-replacement
当添加了 webpack-dev-server 之后,那么每次有代码修改时,就会重新请求页面,然后刷新页面,但这有个小问题,就是即便一个css颜色值修改了,页面也会重新刷新,加入hot-module-replacement可以简化这个请求过程。
首先在devServer中加入 hot:true,然后在 plugins 中加入new webpack.HotModuleReplacementPlugin()配置,这样仅仅只能做到css样式的无刷新修改
如果需要js也能无刷新修改,则需要在js中加入module.hot的判断,判断的对应结果中需要更新代码,使用 module.hot.accept 将其绑定到新的函数执行中,详见https://webpack.docschina.org/guides/hot-module-replacement/#%E5%90%AF%E7%94%A8-hmr
具体针对前端不同框架,社区有不同loader可以支持HMR,React Hot Loader,Vue loader等
15、配置Babel
Babel主要是将es6+代码转换为es5代码,让低版本浏览器也能加载代码
① 最基本的设置是:
npm install --save-dev babel-loader @babel/core

webpack 设置:

module: {
rules: [
{
test: /.js$/,
exclude: /node_modules/,
loader: “babel-loader”
}
]
}
.babelrc 文件设置如下:

npm install @babel/preset-env --save-dev

{
“presets”: ["@babel/preset-env"]
}
但面对更低版本的浏览器的时候,像promise还需要转化注入,就需要引入babel/polyfill


npm install --save @babel/polyfill
在对应业务js代码文件开头引入polyfill import “@babel/polyfill”;

但是这样有个缺点,就是会把所有es6转es5的需要的语法都给打包到对应文件,造成打包文件过大。

如果需要按需去打包polyfill语法,根据代码需要,可以设置文件 .babelrc:

{
“presets”: [["@babel/preset-env", {
“targets”: {
chrome: “67”
},
“useBuiltIns”: “usage”,
}]],
}
上面配置中的 targets 中配置的浏览器版本,是指大于该版本的浏览器,根据该浏览器对es6的支持情况去有针对性的打包polyfill代码,这样可以让打包文件变得更小一点,比如如果chrome67以上的版本浏览器对promise支持很好,那么就不需要打包promise的语法了,更不需要对promise去转码。

总的来说,polyfill修改了全局作用域,浏览器下是window,node下是global。

babel-polyfill主要由两部分组成,core-js和regenerator runtime。

core-js:提供了如ES5、ES6、ES7等规范中 中新定义的各种对象、方法的模拟实现。
regenerator:提供generator支持,如果应用代码中用到generator、async函数的话用到。

引入babel-polyfill全量包后文件会变得非常大。

③ 以上方式需要在对应入口js文件开头引入polyfillimport “@babel/polyfill”;
这种方式会产生一些全局变量,代码量大了之后如写一个大型库或者ui组件库等全局变量会产生变量污染全局。这样就需要用到 transform-runtime,它不会污染全局环境:
npm install --save-dev @babel/plugin-transform-runtime

npm install --save @babel/runtime @babel/runtime-corejs2

删除对应文件开头的引入 import “@babel/polyfill”;

.babelrc 文件设置如下:

{
“plugins”: [["@babel/plugin-transform-runtime",
{
“absoluteRuntime”: false,
“corejs”: 2,
“helpers”: true,
“regenerator”: true,
“useESModules”: false,
}]],
}
@babel/plugin-transform-runtime 会以闭包的形式

16、Tree Shaking
Tree Shaking 用来检测项目中没有被引用的代码(dead-code),Webpack会对这部分代码进行标记,然后在资源压缩打包的时候,从打包出来的文件中去掉,如下示例:
// outer.js

export const foo = () => {
console.log(‘Fucked Up’);
};

export const bar = () => {
console.log(‘Beyond All Repair’);
};

// index.js
import { foo } from ‘./outer’;

foo();
然后配置webpack.config.js文件,添加如下mode和optimization2个配置:

// webpack.config.js
mode: ‘development’,
optimization: {
usedExports: true,
},
然后打包,打开打包好的文件,可以看到如下部分:

// “./src/outer.js”:
/
!
!
!
./src/outer.js ***!
*
****/
/
! exports provided: foo, bar /
/
! exports used: foo /
/
**/ (function(module, webpack_exports, webpack_require) {

“use strict”;
eval("/* harmony export (binding) / webpack_require.d(webpack_exports, “a”, function() { return foo; });\n/ unused harmony export bar */\nvar foo = function foo() {\n console.log(‘Fucked Up’);\n};\nvar bar = function bar() {\n console.log(‘Beyond All Repair’);\n};//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9zcmMvb3V0ZXIuanMuanMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9zcmMvb3V0ZXIuanM/NGJlZiJdLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgY29uc3QgZm9vID0gKCkgPT4ge1xuICBjb25zb2xlLmxvZygnRnVja2VkIFVwJyk7XG59O1xuXG5leHBvcnQgY29uc3QgYmFyID0gKCkgPT4ge1xuICBjb25zb2xlLmxvZygnQmV5b25kIEFsbCBSZXBhaXInKTtcbn07XG4iXSwibWFwcGluZ3MiOiJBQUFBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0EiLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./src/outer.js\n");

/***/ })
其中有2行注释说明了:

/*! exports provided: foo, bar /
/
! exports used: foo */
就是打包文件中还是导出了foo和bar两个方法,但只用到了foo,这说明在development中代码的tree shaking只是找出来了并告知了,但并没有真的去删除这部分没用到的代码,webpack4新增了mode,将其设置为production后,不用设置optimization,就会真实执行tree shaking:

// webpack.config.js
mode: ‘production’,
因为设置了mode: 'production’后代码被作了minify(压缩)和 mangle(混淆破坏),foo和bar方法已经搜不到了,但是方法体中的console内容还是可以搜的,可以发现,foo中的console内容Fucked Up还可以搜到,而bar中的console内容Beyond All Repair已经搜不到了,因为已经被删除了。

webpack4新增了一个例外处理的口子,就是在package.json中配置一个sideEffects属性,来设置哪些文件是永远都不会被删除掉的,如果设置了sideEffects: false,那么则会正常的删除未被用到的代码。如果设置了sideEffects: ["@babel/polly-fill"]则表明,即便@babel/polly-fill没被直接应用,但还是会在打包时,将它打包进来。

Tree Shaking的注意事项(来至官网):
使用 ES2015 模块语法(即 import 和 export)。
确保没有 compiler 将 ES2015 模块语法转换为 CommonJS 模块(这也是流行的 Babel preset 中 @babel/preset-env 的默认行为)。
在项目 package.json 文件中,添加一个 “sideEffects” 属性。
通过将 mode 选项设置为 production ,启用 minification (代码压缩) 和 tree shaking。
17、Mode: development/production
wenpack4新增了mode配置:

设置mode: ‘development’
会将 process.env.NODE_ENV 的值设为 development
启用 NamedChunksPlugin 和 NamedModulesPlugin。
设置mode: ‘production’
会将 process.env.NODE_ENV 的值设为 production
启用 FlagDependencyUsagePlugin
FlagIncludedChunksPlugin
ModuleConcatenationPlugin
NoEmitOnErrorsPlugin
OccurrenceOrderPlugin
SideEffectsFlagPlugin
UglifyJsPlugin
0人点赞
Code.life

发布了43 篇原创文章 · 获赞 7 · 访问量 4613

猜你喜欢

转载自blog.csdn.net/qq_46522785/article/details/105023146