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> tag
如果配置style-loader/url
,则会生成一个类似<link rel="stylesheet" href="path/to/file.css">
这样的内联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: /\.less$/,
include: /node_modules\/antd/,
use: [
'style-loader',
{ loader: 'css-loader', options: {modules: false} },
'less-loader'
]
},
{
test: /\.less$/,
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是按照要求配置的,如加上
<div id="root"></div>
,那么就可以在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文件开头引入polyfill
import "@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
和optimization
2个配置:
// 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
- 会将