简介
什么是 webpack
webpack is a module bundler (模块打包工具)
webpack 可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其他的一些浏览器不能直接运行的拓展语言(scss, TypeScript 等),并将其打包为合适的格式以供浏览器使用。
安装
环境:nodejs https://nodejs.org/en/
版本参考官网发布的最新版本,可以提升 webpack 的打包速度
全局安装(不推荐)
1
2
3
4
5
6
7npm install webpack webpack-cli -g
webpack-cli 可以帮助我们在命令行里使用 npx, webpack等命令
webpack -v
npm unistall webpack webpack-cli -g
MacOS进行全局安装需要权限,命令前加上 sudo局部安装 项目内安装
1
npm install webpack webpack-cli --save-dev # -D
安装指定版本
1
2
3npm info webpack # 查看 webpack 的历史发布信息
npm install webpack@x.xx webpack-cli -D
检查是否安装成功
1 | webpack -v # 查看 webpack 版本(全局安装才能查看) |
测试:启动 webpack 打包
1 |
|
1 | npx webpack # 打包命令,使用webpack处理index.js这个文件 |
总结:webpack是一个模块打包工具,可以识别出引入模块的语法,早期的 webpack 只是个 js 模块的打包工具,现在可以使 css,png,vue 的模块打包工具
webpack 配置文件
零配置是很弱的,特定的需求,总是需要自己进行配置
1 | module.exports = { |
当我们使用 npx webpack
,表示的是使用 webpack 处理打包,./src/index.js
为入口模块。默认出口放在当前目录下的 dist 目录,打包后的模块名称是 main.js,当然我们可以自行修改
webpack 有默认的配置文件,webpack.config.js ,我们可以对这个文件进行修改,进行个性化配置
默认配置文件:wbepack.config.js
1
npx webpack # 执行命令后,webpack 会找到默认的配置文件,并使用执行
不使用默认的配置文件:webpackconfig.js
1
npx webpack --config webpackconfg.js # 指定webpack使用webpackconfig.js文件作为配置文件
修改 package.json scripts 字段,使用
npm run xxx
来启动原理:模块局部安装会在 node_modules/.bin 目录下创建一个软链接
1
2
3"scripts": {
"dev": "webapck"
}1
npm run dev
webpack.config.js 配置结构
1 | module.exports = { |
webpack 核心概念
entry
指定 webpack 打包入口文件,webpack执行构建的第一步将从 entry 开始,可抽象成输入
1 | module.exports = { |
output
打包转换后的文件输出到磁盘位置以输出结果,在webpack经过一系列处理并得出最终代码后输出结果
1 | module.exports = { |
mode
mode 用来指定当前的构建环境
- production
- development
- none
选项 | 描述 |
---|---|
development |
设置 process.env.NODE_ENV 的值为 development ,开启 NamedChunksPlugin 和 NamedModulesPlugin |
production |
设置 process.env.NODE_ENV 的值为 production ,开启 FlagDependencyUsagePlugin ,FlagIncludedChunksPlugin ,ModuleConcatenationPlugin ,NoEmitOnErrorsPlugin ,OccurrenceOrderPlugin ,SideEffectsFlagPlugin 和 TerserPlugin |
node |
不开启任何优化选项 |
如果没有设置,webpack 会将 mode
的默认值设置为 production
。
记住,设置
NODE_ENV
并不会自动的设置mode
开发阶段的开启会有利于热更新的处理,识别哪个模块变化
生产阶段的开启会有帮助模块压缩,处理副作用等一些功能
loader
模块解析,模块转换器,用于把模块原内容按照需求转换成新内容
webpack 是模块打包工具,儿模块不仅仅是 js,还可以是 css,图片或者其他格式
但是 webpack 默认只知道处理 js 和 json 模块,那么其他格式的模块处理和处理方式就需要 loader
常见的 loader
1 | style-loader |
module
模块,在 webpack 里一切皆模块,一个模块对应一个文件,webpack 会从配置的 entry 开始递归找出所有依赖的模块
1 | module: { |
当 webpack 处理到不认识的模块时,需要再 webpack 中的 module 里进行配置,当检测到是什么格式的模块,使用什么 loader 来处理
file-loader
处理静态资源模块
原理是把打包入口中识别出的资源模块,移动到输出目录,并且返回一个地址名称
使用场景:
当我们需要模块仅仅是从源代码挪移到打包目录,就可以使用 file-loader 来处理,txt, svg, csv, excel, 图片等资源
1 | npm install file-loader -D |
处理图片
案例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15module: {
rules: [
{
test: /.(png|jpe?g|gif)$/,
use: {
loader: 'file-loader',
options: {
name: '[name]_[hash].[ext]',
outputPath: 'images/',
publicPath: '../images'
}
}
}
]
}1
2
3
4
5
6
7
8import logo from './webpack.jpg'
let img = new Image();
img.src = logo;
img.classList.add('logo');
let root = document.getElementById('root');
root.append(img)处理字体
1
2
3
4
5
6
7
8
9
10
11
12// css
@font-face {
font-family: "webfont";
font-display: swap;
src: url("webfont.woff2") format("woff2");
}
body {
font-size: 24px;
font-family: "webfont";
background-color: #f40;
}1
2
3
4
5// webpack.config.js
{
test: /.(eot|ttf|woff|woff2|svg)$/,
use: 'file-loader'
}
url-loader
url-loader 内部使用了 file-loader,所以可以处理 file-loader 所有的事情,但是遇到 体积较小图片模块会把该图片转换为 base64 格式字符串,并打包到 js 里。对小体积的图片比较适合,大图片得不偿失。
1 | npm install url-loader -D |
案例:
1 | module: { |
样式处理
css-loader 分析模块之间的关系,并合成一个css
style-loader 会把 css-loader 生成的内容,以style标签包裹并挂载到页面的head部分
1 | npm install style-loader css-loader -D |
1 | // webpack.config.js |
Less 样式处理
less-loader 把 less 语法转换为 css
1
npm i less less-loader -D
案例:
loader 有顺序,从右到左,从下到上
1
2
3
4
5// webpack.config.js
{
test: /.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
}样式自动添加前缀,兼容
postcss-loader
1
npm i postcss-loader autoprefixer -D
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19// webpack.config.js
{
test: /.less$/,
use: [
'style-loader',
'css-loader',
'less-loader',
{
loader: 'postcss-loader',
options: {
plugins: () => [
require('autoprefixer')({
overrideBrowserslist: ['last 2 versions', '>= 1%']
})
]
}
}
]
}可以直接在 webpack.config.js 中直接配置,也可以将 postcss 提取出来成一个文件 postcss.config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14// webpack.config.js
{
test: /.css$/,
use: ['style-loader', 'css-loader', 'postcss-loadr']
}
// postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')({
overrideBrowserslist: ['last 2 versions', '>= 1%']
})
]
}
Plugins
plugin 可以在 webpack运行到某个阶段的时候,帮你做一些事情,类似于生命周期的概念
扩展插件,在 webpack 构建流程中的特定时机注入扩展逻辑来改变构建结果或做你想要的事情,作用于整个构建过程
HtmlWebpackPlugin
html-webpack-plugin 会在打包结束后,自动生成一个 html 文件,并把打包的生成的 js 模块注入到该 html 中
1 | npm i html-webpack-plugin -D |
配置
Name | Type | Default | Description | |||||||
---|---|---|---|---|---|---|---|---|---|---|
title |
{String} |
Webpack App |
The title to use for the generated HTML document | |||||||
filename |
{String} |
'index.html' |
The file to write the HTML to. Defaults to index.html . You can specify a subdirectory here too (eg: assets/admin.html ) |
|||||||
template |
{String} |
`` | webpack relative or absolute path to the template. By default it will use src/index.ejs if it exists. Please see the docs for details |
|||||||
templateParameters |
`{Boolean | Object | Function}` | `` | Allows to overwrite the parameters used in the template - see example | |||||
inject |
`{Boolean | String}` | true |
`true | ‘head’ | ‘body’ | falseInject all assets into the given templateor templateContent. When passing trueor ‘body’all javascript resources will be placed at the bottom of the body element. ‘head’` will place the scripts in the head element - see the inject:false example |
|||
favicon |
{String} |
`` | Adds the given favicon path to the output HTML | |||||||
meta |
{Object} |
{} |
Allows to inject meta -tags. E.g. meta: {viewport: 'width=device-width, initial-scale=1, shrink-to-fit=no'} |
|||||||
base |
`{Object | String | false}` | false |
Inject a base tag. E.g. base: "https://example.com/path/page.html |
|||||
minify |
`{Boolean | Object}` | true if mode is 'production' , otherwise false |
Controls if and in what ways the output should be minified. See minification below for more details. | ||||||
hash |
{Boolean} |
false |
If true then append a unique webpack compilation hash to all included scripts and CSS files. This is useful for cache busting |
|||||||
cache |
{Boolean} |
true |
Emit the file only if it was changed | |||||||
showErrors |
{Boolean} |
true |
Errors details will be written into the HTML page | |||||||
chunks |
{?} |
? |
Allows you to add only some chunks (e.g only the unit-test chunk) | |||||||
chunksSortMode |
`{String | Function}` | auto |
Allows to control how chunks should be sorted before they are included to the HTML. Allowed values are `’none’ | ‘auto’ | ‘dependency’ | ‘manual’ | {Function}` | ||
excludeChunks |
{Array.<string>} |
`` | Allows you to skip some chunks (e.g don’t add the unit-test chunk) | |||||||
xhtml |
{Boolean} |
false |
If true render the link tags as self-closing (XHTML compliant) |
clean-webpack-plugin
1 | npm i clean-webpack-plugin -D |
mini-css-extract-plugin
1 | npm i mini-css-extract-plugin -D |
1 | // webpack.config.js |
sourceMap
源代码与打包后的代码的映射关系
在 development 模式中,默认开启,可以在配置文件中设置
1 | devtool: 'none' |
devtool 的介绍:https://www.webpackjs.com/configuration/devtool/
eval: 速度最快,使用 eval 包裹模块代码
source-map:产生
.map
文件cheap:较快,不用管列的信息,也不包含 loader 的 sourceMap
module:第三方模块,包含loader的sourceMap(比如 jsx to js,babel)
inline:将
.map
作为 DataURI 嵌入,不单独生成.map
文件
配置推荐
1 | devtool: 'cheap-module-eval-source-map'; // 开发环境配置 |
WebpackDevServer
提升开发效率的利器
因为每次改完代码都需要重新打包一次,打开浏览器,刷新一次,很麻烦
安装 webpack-dev-server 改善体验
启动服务后,会发现 dist 目录为空,这是因为 DevServer 吧打包后的模块放到内存中,从而提升速度
1 | npm i webpack-dev-server -D |
修改 package.json
1 | // package.json |
配置
1 | // webpack.config.js |
跨域
联调期间,前后端分离,直接获取数据会跨域,上线后我们使用 Nginx 转发,开发期间,webpack 就能搞定
启动一个服务器,mock 一个借口
1 | // npm i express -D |
1 | npm i axios -D |
1 | // index.js |
!!会产生跨域问题
修改 webpack.config.js 设置服务器代理
1 | // webpack.config.js |
修改 index.js
1 | // index.js |
搞定!
- 和服务器约定好接口,定义好字段
- 接口文档啥时候给到
- 根据接口文档mock数据,mock接口
文件监听
轮询判断文件的最后编辑事件是否变化,某个文件发生变化,并不会立即告诉监听者,先缓存起来
webpack 开启监听模式,有两种
启动 webpack 命令,带上
--watch
参数,启动监听后,还是需要手动刷新浏览器1
2
3scripts: {
"watch": "webpack --watch"
}在配置文件里设置
watch: true
1
2
3
4
5
6
7
8module.exports = {
watch: true, // 默认 false
watchOptions: { // 配合 watch: true
ignored: /node_modules/, // 忽略的目录
aggregateTimeout: 300, // 监听到文件变化后,等待300ms再去执行,默认300ms
poll: 1000 // 轮询周期,每秒1次,1000ms
}
}
HMR
Hot Module Replacement (热模块替换)
启动 HMR
1 | // webpack.config.js |
配置文件头部引入 webpack
1 | // webpack.config.js |
在插件配置处添加
1 | plugins: [ |
案例:
1 | // index.js |
1 | // index.css |
注意:启动HMR后,css抽离会不生效,不支持 contenthash,chunkhash
处理 js 模块 HMR
需要使用 module.hot.accept 来观察模块更新
案例:
1 | // counter.js |
Babel
官方网站:https://babeljs.io/
1 | npm i babel-loader @babel/core @babel/preset-env -D |
测试代码
1 | // index.js |
webpack.config.js
1 | { |
通过上面几部还不够,Promise 等一些特性还没有转换过来,这时候需要借助 @babel/polyfill
,把 es6 的新特性都装进来,来弥补低版本浏览器中缺失的特性
@babel/polyfill
以全局变量的方式注入进来,windows.Promise 会污染全局变量
1 | npm i @babel/polyfill -S |
1 | // webpack.config.js |
1 | // index.js 顶部 |
虽然这样实现了,但是打包的体积大了不少,应为 polyfill 默认会把所有的特性注入进来,假如我想我⽤到的es6+,才会注⼊,没⽤到的不注⼊,从⽽减少打包 的体积,可不可以呢?
当然可以
修改 webpack.config.js
1 | // webpack.config.js |
当开发的是组件库,工具库这些场景的时候,polyfill 就不合适了,因为 polyfill 是注入到 全局变量window下,会污染全局变量,所以推荐闭包方式:@babel/plugin-transform-runtime
@babel/plugin-transform-runtime
它不会造成全局污染
1 | // .babelrc |
useBuiltIns
选项是 babel 7
的新功能,这个选项告诉 babel
如何配置 @babel/polyfill
三个参数
- entry 需要在 webpack 的入口文件里
import '@babel/polyfill'
一次。babel
会根据你的使用情况导入垫片,没有使用的功能不会被导入相应的垫片 - usage 不需要
import
,全自动检测,但是要安装@babel/polyfill
(试验阶段) - false 如果你
import "@babel/polyfill"
,它不会排除掉没有使用的垫片,程序体积很庞大(不推荐)
请注意:usage 的行为类似 babel-tranform-runtime,不会造成 全局污染,因此也不会对类似 Array.prototype.includes() 进行 polyfill
扩展:
.babelrc 文件
新建 .babelrc 文件,把 options 部分移入到该文件中就可以了
1 | // .babelrc |
配置 React 环境
安装 react 环境
1 | npm i react react-dom -S |
编写 react 代码
1 | // index.js |
安装 babel 和 react 转换的插件
1 | npm i @babel/preset-react --save-dev |
1 | // .babelrc |
扩展:多页面打包通用方案
1 | entry:{ |
- 目录结构调整
- src
- index
- index.js
- index.html
- list
- index.js
- index.html
- detail
- index.js
- index.html
- index
- 使用 glob.sync 第三方库来匹配路径
1 | npm i glob -D |
1 | const glob = require('glob') |
1 | // MPA 多页面打包通用方案 |
1 | const setMPA = () => { |
webpack 打包原理
webpack 在执⾏npx webpack进⾏打包后,都⼲了什么事情?
1 | (function (modules) { // webpackBootstrap |
⼤概的意思就是,我们实现了⼀个webpack_require 来实现⾃⼰的模块化,把代码都缓存在installedModules⾥,代码⽂件以对象传递进来,key 是路径,value是包裹的代码字符串,并且代码内部的require,都被替换成了webpack_require
实现一个 bundle.js
模块分析:读取入口文件,分析代码
1
2
3
4
5
6
7
8const fs = require('fs')
const moduleAnalyser = filename => {
const content = fs.readFileSync(filename, 'utf-8')
console.log(content)
}
moduleAnalyser('./index.js')拿到⽂件中依赖,这⾥我们不推荐使⽤字符串截取,引⼊的模块名越多,就越麻烦,不灵活,这⾥我们推荐使⽤@babel/parser,这是babel7的⼯具,来帮助我们分析内部的语法,包括es6,返回⼀个 ast 抽象语法树
@babel/parser https://babeljs.io/docs/en/babel-parser
安装 @babel/parser
1
npm i @babel/parser --save
bundle.js
1
2
3
4
5
6
7
8
9
10
11
12
13const fs = require('fs')
const parser = require('@babel/parser')
const moduleAnalyser = filename => {
const content = fs.readFileSync(filename, 'utf-8')
const ast = parser.parse(content, {
sourceType: 'module'
})
console.log(ast.program.body)
}
moduleAnalyser('./index.js')接下来我们就可以根据body⾥⾯的分析结果,遍历出所有的引⼊模 块,但是⽐较麻烦,这⾥还是推荐babel推荐的⼀个模块@babel/traverse,来帮我们处理。
1
npm i @babel/traverse --save
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25const fs = require('fs')
const path = require('path')
const parser = require('@babel/parser')
const traverse = require('@babel/traverse').default
const moduleAnalyser = filename => {
const content = fs.readFileSync(filename, 'utf-8')
const ast = parser.parse(content, {
sourceType: 'module'
})
const dependecies = [];
// 分析ast抽象语法树,根据需要返回对应数据,
// 根据结果返回对应的模块,定义⼀个数组,接受⼀下node.source.value的值
traverse(ast, {
ImportDeclaration ({ node }) {
console.log(node)
dependecies.push(node.source.value)
}
})
console.log(dependecies)
}
moduleAnalyser('./index.js')
最终结果图片
分析上图,我们要分析出信息:
- 入口文件
- 入口文件引入的模块
- 引入路径
- 在项目中里的路径
- 可以在浏览器中执行的代码
处理现在的路径问题
1 | // 需要⽤到path模块 |
把代码处理成浏览器可运⾏的代码,需要借助@babel/core,和 @babel/preset-env,把ast语法树转换成合适的代码
1 | const babel = require('@babel/core') |
到处所有分析出的信息
1 | return { |
完成代码参考
1 | const fs = require('fs') |
分析依赖
上一步我们已经完成了一个模块的分析,接下来我们要完成项目里所有模块的分析
1 | const fs = require('fs') |
- 生成代码
1 | const fs = require('fs') |
node 调试工具使用
修改 scripts
1
"debug": "ndoe --inspect --inspect-brk ndoe_modules/webpack/bin/webpack.js"
如何自己编写一个 Loader
⾃⼰编写⼀个Loader的过程是⽐较简单的,
Loader就是⼀个函数,声明式函数,不能⽤箭头函数
拿到源代码,作进⼀步的修饰处理,再返回处理后的源码就可以了
官⽅⽂档:https://webpack.js.org/contribute/writing-a-loader/
接⼝⽂档:https://webpack.js.org/api/loaders/
简单案例
创建⼀个替换源码中字符串的loader
1
2
3
4
5
6
7
8
9
10// index.js
console.log('hello kkb')
// replaceLoader.js
module.exports = function (source) {
console.log(source, this, this.query)
return source.replace('kkb', '开课吧')
}
// 需要⽤声明式函数,因为要上到上下⽂的this,⽤到this的数据,该函数接受⼀个参数,是源码在配置文件中使用 loader
1
2
3
4
5
6
7
8
9
10// 需要使用 node 核心模块 path 来处理路径
const path = require('path')
module: {
rules: [
{
test: /.js$/,
use: path.resolve(__dirname, './loader/replaceLoader.js')
}
]
}如何给 loader 配置参数,loader 如何接受参数?
- this.query
- loader-utils
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// webpack.config.js
module: {
rules: [
{
test: /.js$/,
use: [
{
loader: path.resolve(__dirname, './loader/replaceLoader.js'),
options: {
name: '开课吧'
}
}
]
}
]
}
// replaceLoader.js
const loaderUtils = require("loader-utils"); //官⽅推荐处理 loader,query的⼯具
module.exports = function(source) {
// this.query 通过this.query来接受配置⽂件传递进来的参数
// return source.replace("kkb", this.query.name);
const options = loaderUtils.getOptions(this);
const result = source.replace("kkb", options.name);
return source.replace("kkb", options.name);
}this.callback 如何返回多个信息,不只是处理好的源码,可以使用 this.callback 来处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// replaceLoader.js
const loaderUtils = require("loader-utils"); // 官⽅推荐处理 loader,query的⼯具
module.exports = function(source) {
const options = loaderUtils.getOptions(this);
const result = source.replace("kkb", options.name);
this.callback(null, result);
};
// this.callback(
err: Error | null,
content: string | Buffer,
sourceMap?: SourceMap,
meta?: any
);this.async 如果 loader 里面有异步事件要怎么处理
1
2
3
4
5
6
7
8
9const loaderUtils = require("loader-utils")
module.exports = function (source) {
const options = loaderUtils.getOptions(this)
setTimeout(() => {
return source.replace('kkb', options.name)
}, 1000)
}
// 先用 setTimeout 处理下试试,发现会报错我们使用 this.async来处理,他会返回 this.callback
1
2
3
4
5
6
7
8
9
10
11
12const loaderUtils = require("loader-utils")
module.exports = function (source) {
const options = loaderUtils.getOptions(this)
// 定义⼀个异步处理,告诉webpack,这个loader⾥有异步事件,在⾥⾯调⽤下这个异步
// callback 就是 this.callback 注意参数的使⽤
const callback = this.async();
setTimeout(() => {
const result = source.replace('kkb', options.name)
callback(null, result)
}, 1000)
}多个 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
29
30
31
32
33
34// replaceLoader.js
module.exports = function (source) {
return source.replace('开课吧', 'word')
}
// replaceLoaderAsync.js
const loaderUtils = require("loader-utils")
module.exports = function (source) {
const options = loaderUtils.getOptions(this)
// 定义⼀个异步处理,告诉webpack,这个loader⾥有异步事件,在⾥⾯调⽤下这个异步
const callback = this.async();
setTimeout(() => {
const result = source.replace('kkb', options.name)
callback(null, result)
}, 1000)
}
// webpack.config.js
module: {
rule: [
{
test: /.js$/,
use: [
path.resolve(__dirname, './loader/replaceLoaderAsync.js'),
{
loader: path.resolve(__dirname, './loader/replaceLoaderAsync.js'),
options: {
name: '开课吧'
}
}
]
}
]
}顺序,从上而下,从右到左
处理 loader 的路径问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19resolveLoader: {
modules: ['node_modules', './loader']
},
module: {
rules: [
{
test: /.js$/,
use: [
'replaceLoader',
{
loader: 'replaceLoaderAsync',
options: {
name: '开课吧'
}
}
]
}
]
}
参考:loader API
https://webpack.js.org/api/loaders
如何自己编写一个 Plugins
Plugin 开始打包,在某个时刻,帮助我们处理⼀些什么事情的机制
plugin要⽐loader稍微复杂⼀些,在webpack的源码中,⽤plugin的机制还是占有⾮常⼤的场景,可以说plugin是webpack的灵魂
设计模式
事件驱动
发布订阅
plugin是⼀个类,⾥⾯包含⼀个apply函数,接受⼀个参数,compiler
官⽅⽂档:https://webpack.js.org/contribute/writing-a-plugin/
案例:
创建 copyright-webpack-plugin.js
1
2
3
4
5
6
7
8class CopyrightWebpackPlugin {
constructor () {}
// compiler webpack 实例
apply (compiler) {}
}
module.exports = CopyrightWebpackPlugin配置文件里使用
1
2
3const CopyrightWebpackPlugin = require('./plugin/copyright-webpack-plugin')
plugins: [new CopyrightWebpackPlugin()]如何传递参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17// webpack.config.js
plugins: [
new CopyrightWebpackPlugin({
name: '开课吧'
})
]
// copyright-webpack-plugin.js
class CopyrightWebpackPlugin {
constructor(options) {
// 接收参数
console.log(options)
}
apply(compiler) {}
}
module.exports = CopyrightWebpackPlugin配置 Plugin 在什么时刻进行
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
31class CopyrightWebpackPlugin {
constructor (options) {}
apply (compiler) {
// hooks.emt 定义在某个时刻
compiler.hooks.emit.tapAsync(
"CopyrightWebpackPlugin",
(compilation, cb) => {
compilation.assets['copyright.txt'] = {
source: function () {
return 'hello copy'
},
size: function () {
return 20
}
}
cb()
}
)
// 同步的写法
/*
compiler.hooks.compile.tap(
'CopyrightWebpackPlugin',
compilation => {
// ...
}
)
*/
}
}
module.exports = CopyrightWebpackPlugin
参考:compiler-hooks
https://webpack.js.org/api/compiler-hooks
tree shaking
webpack 2.x 开始支持 tree shaking 概念,顾名思义,摇树,只支持ES module 的引入方式!!!!
1 | // webpack.config.js |
1 | // package.json |
开发模式设置后,不会帮助我们把没有引用的代码去掉
code spliting
代码分割,比如讲一些第三方库抽离,形成单独的文件
This is copyright.