第一章 安装webpack
$ npm install -g webpack
创建项目目录
$ mkdir webpack
$ cd webpack
$ mkdir day01
$ cd day01
$ mkdir src
webpack
┗━day01
┗━src
┗━index.js
命令行方式简单入门
在 index.js中编写代码:
console.log('hello webpack')
在 day01 目录执行:
$ webpack ./src/index.js ./dest/index.js
此时 day01 目录下多了 dest 目录,里面有一个 index.js,打开这个文件可以看到 webpack自动生成了很多代码,在文件末尾可以找到 我们在 src/index.js写的代码在里面:
/***/ (function(module, exports) {
console.log('hello webpack')
/***/ })
文件引用
/day01/user.js
export default function (first_name, last_name) {
console.log('hello ' + first_name + '-' + last_name);
}
/day01/index.js
let getUserName = require('./user')
console.log('hello webpack')
getUserName('Liu', 'DeHua')
再次执行 $ webpack ./src/index.js ./dest/index.js
进行打包,此时 /dest/index.js文件已把所有的代码都打包进去了。
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
let getUserName = __webpack_require__(1)
console.log('hello webpack')
getUserName('Liu', 'DeHua')
/***/ }),
/* 1 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony default export */ __webpack_exports__["default"] = (function (first_name, last_name) {
console.log('hello ' + first_name + '-' + last_name);
});
/***/ })
/******/ ]);
命令格式说明
$ webpack <entry> [<entry>] <output>
- entry: 入口文件,可以一个或多个
- output: 输出文件
// entry可以有多个,但是一个和多个写法不同,必须以 entryname=filename的形式指定,
// 同时不能单纯地指定输出的文件名称,比如 ./dest/index.js,这将会报错。可使用以下方式指定。
$ webpack index1=./src/index.js index2=./src/index2.js ./dest/[name].js
- entry文件名为 index.js时可省略,webpack会自动在指定文件夹下寻找该文件。
使用配置文件
最简单的配置文件
/day01/webpack.config.js
var path = require('path')
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dest'), // path需绝对路径,所以引用node.js的 path模块
filename: 'index.js'
}
}
在 /day01/ 执行命令 $ webpack
这里实现了之前使用的命令 $ webpack ./src/index/js ./dest/index.js
的功能,webpack命令自动读取目录下名为 webpack.config.js
的配置文件。
注意
- 配置文件的名称不一定是
webpack.config.js
,如果不是则需显示指定配置文件名:$ webpack --config <path/to/config/file>
output
的path
必须为绝对路径,所以使用node.js
的path
模块
监听文件变化
使用 $ webpack -w
可以监听入口文件变化,包括入口文件引入的所有文件的变化,做到源码更改时浏览器自动刷新
webpack一直监听文件改变,文件发生变化会触发再次打包,同事控制台输出重新打包后的信息。要停止监听,在 控制台按 Ctrl + C
修改 webpack 配置文件
修改 webpack 配置文件
后,需要重启 webpack,新的配置才生效,即 Ctrl + C
停止后,再执行 $ webpack
打包过程错误提示
在打包过程中出现错误, webpack 将会在控制台提示,并且在修复后会再次打包
详解
详解 entry
entry 可以取以下类型的值:
- string:
'index.js'
- array:
[ 'index.js', 'index2.js' ]
- object:
{ index: 'index1.js', index2: 'index2.js' }
- function:
function () { return 'index1.js' }
详解 output
只有一个 entry 时,可直接指定 output.filename, 但有多个 entry 时不能直接指定,否则报错
错误写法: $ webpack index1=./src/index.js index2=./src/index2.js ./dest/index.js
需要指定其他方式:
[name].js
: 使用 entry 名字[id].js
: 使用 chunk id[hash].js
: 使用哈希[chunkhash].js
: 使用生成的文件的哈希(推荐)
以上方式可以结合使用,推荐使用[name].[chunkhash].js
, 既能知道哪个是entry
,也能让文件没有修改时候保持文件名不变,用户在网站更新后访问可直接从缓存读取文件。
webpack 指令说明
webpack
: 根据webpack.config.js
打包,如果没有该文件将会报错webpack --config <path/to/config/file>
: 根据指定的配置文件打包,如果没有该文件将报错
eg:webpack --config webpack.config.js
webpack -w
: 根据指定默认配置文件打包,并监听文件变化,在变化后自动打包webpack -p
: 打包的时候对 js 混淆压缩
第二章 devServer自动刷新
浏览器自动刷新
创建新项目 day02
webpack
┗━day01 // 上面内容的项目
┗━day02 // 创建的新项目
┗━src
┗━index.js
初始化项目,在控制台运行 $ npm init -y
指令,生成 package.json
,管理依赖包
By the way,
$ npm init [-f|--force|-y|--yes]
使用了 -f(代表force)、-y(代表yes),则跳过提问阶段,直接生成一个新的 package.json 文件
/day02/package.json
{
"name": "web-auto-refresh",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
创建 ./src/index.js
和 ./src/index.html
,在html中 引用 js
./src/index.js
console.log('hello webpack')
./src/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>web-auto-refresh</title>
<script type="text/javascript" src="./index.js"></script>
</head>
<body>
</body>
</html>
复制上面最简单的配置文件
webpack.config.js
var path = require('path')
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dest'),
filename: 'index.js'
}
}
配置 devServer
var path = require('path')
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dest'),
filename: 'index.js'
}
// 以上为最简单配置
devServer: {
contentBase: path.join(__dirname, 'dest'),
port: 9000
}
}
devServer
提供了一个 web 服务器
contentBase
: 为该服务器的根目录,它将以此来寻找资源port
: 为服务器端口
安装 webpack-dev-server
、 webpack
$ npm install webpack --save-dev
$ npm install webpack-dev-server -g
// 安装后执行 webpack -v提示需要安装 webpack-cli
F:\code\webpack\day02>webpack-dev-server -v
The CLI moved into a separate package: webpack-cli.
Please install 'webpack-cli' in addition to webpack itself to use the CLI.
-> When using npm: npm install webpack-cli -D
-> When using yarn: yarn add webpack-cli -D
// 于是执行
$ npm install webpack-cli -D
// 执行 $ webpack-dev-server -v 还是报错,按错误提示,webpack单独分离出了wepack-cli,需要我们安装wepack-cli。
// 全局安装 webpack-cli
$ npm i -g webpack-cli
// 控制台执行 webpack-dev-server依然报错
// Error: Cannot find module 'webpack/schemas/WebpackOptions.json'
这时查资料说在本地装 webpack
, 于是 $ npm install webpack --save-dev
,装了还是报错。
索性全部包进行本地安装:
$ npm install webpack --save-dev
$ npm install webpack-cli --save-dev
$ npm install webpack-dev-server --save-dev
// 安装完成 package.json 文件依赖如下:
"devDependencies": {
"webpack": "^4.10.0",
"webpack-cli": "^2.1.4",
"webpack-dev-server": "^3.1.4"
}
启动 devServer
$ webpack-dev-server
// 输出
F:\code\webpack\day02>webpack-dev-server
i 「wds」: Project is running at http://localhost:9000/
i 「wds」: webpack output is served from /
i 「wds」: Content not from webpack is served from F:\code\webpack\day02\dest
‼ 「wdm」: Hash: a2da9370420e5ac31303
Version: webpack 4.10.0
Time: 2917ms
Built at: 2018-05-29 16:54:32
Asset Size Chunks Chunk Names
index.js 139 KiB 0 [emitted] main
Entrypoint main = index.js
在浏览器打开 http://localhost:9000 就可以访问这个网站了。
devServer其他配置
compress
: 是否gzip
压缩host
: 访问地址,默认是localhost
,但可以配置成0.0.0.0
, 就可以使用127.0.0.1
访问index
: 不指定访问资源时,默认访问contentBase
路径下的index.html
文件,可以通过index
改变默认访问文件open
: 执行webpack-dev-server
: 后自动打开一个浏览器窗口progress
: 显示打包进度,用于命令行
注意
配置指令分2种,只在终端使用的,如: progress
,只能在终端指定 webpack-dev-server --progress
;一种可以在终端也可以在配置文件,比如 compress
,在配置文件中 compress: true
, 在终端 webpack-dev-server --compress
。在终端中指定使用 -
连接每个指令,在配置文件中,使用驼峰法指定。
可以使用 npm
的 script
功能,快速调用 webpack-dev-server
package.json
"scripts": {
"dev": "webpack-dev-server --progress",
"build": "webpack -p"
}
在控制台可以这样使用
$ npm run dev
$ num run build
本章源码
至此,我们的 webpack-dev-server
代码如下:
var path = require('path')
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dest'),
filename: 'index.js'
},
// 以上为最简单配置
devServer: {
contentBase: path.join(__dirname, ''),
port: 9000,
compress: true,
open: true,
host: 'localhost',
index: 'index.html'
}
}
package.json:
{
"name": "web-auto-refresh",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "webpack-dev-server --progress",
"build": "webpack -p",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^4.10.0",
"webpack-cli": "^2.1.4",
"webpack-dev-server": "^3.1.4"
}
}
第三章 生成html模板
上一章的学习配置,现在可以自动刷新浏览器了,这章学习插件。第一个插件解决上一章的一个问题,
index.html
需要手动插入打包好的js, 同事不会将index.html
一起放到dest
文件夹下的问题。
创建新项目
复制上一章的项目,删除dest文件夹
安装 html-webpack-plugin
$ npm install html-webpack-plugin --save-dev
配置 html-webpack-plugin
在 webpack.congif.js 中添加 html-webpack-plugin 的配置
var HtmlWebpackPlugin = require('html-webpack-plugin')
// 添加插件
plugins: [
new HtmlWebpackPlugin()
]
最终配置文件 webpack.config.js
var path = require('path')
// 引入 html打包插件
var HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.js'
},
// 以上为最简单配置,指定了入口和输出
// 配置 webpack-dev-server
devServer: {
contentBase: path.resolve(__dirname, 'dist'), // path.join(__dirname, ''),
port: 9000,
compress: true,
open: true,
host: 'localhost',
index: 'index.html'
},
// 插件声明
plugins: [
new HtmlWebpackPlugin()
]
}
打包
在控制台执行 $ npm run build
/dist 文件夹生成了2个文件
index.js
:webpack
打包生成的js 文件index.html
:html-webpack-plugin
自动生成
index.html
文件中, html-webpack-plugin
添加了对打包生成的 index.js
的引用。
/dist/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Webpack App</title>
</head>
<body>
<script type="text/javascript" src="index.js"></script></body>
</html>
html-webpack-plugin配置
配置自定义title
/webpack.config.js
new HtmlWebpackPlugin({
title: 'html-webpack-plugin配置的title'
})
$ npm run build
打包后的 /dist/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>html-webpack-plugin配置的title</title>
</head>
<body>
<script type="text/javascript" src="index.js"></script></body>
</html>
自定义文件名
/webpack.config.js
添加配置
new HtmlWebpackPlugin({
title: '自定义标题',
filename: 'admin.html'
})
$ npm run build
后在 dist 文件夹中生成 admin.html 和 index.js
根据模板生成
添加模板文件 ./template.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<h1>这是一个模板文件</h1>
</body>
</html>
添加配置
new HtmlWebpackPlugin({
title: 'html-webpack-plugin配置的title',
filename: 'admin.html',
template: path.resolve(__dirname, 'template.html')
})
$ npm run build
打包,之后的 /dist/admin.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<h1>这是一个模板文件</h1>
<script type="text/javascript" src="index.js"></script></body>
</html>
自定义 js 文件注入位置
添加配置
new HtmlWebpackPlugin({
title: 'html-webpack-plugin配置的title',
filename: 'admin.html',
template: path.resolve(__dirname, 'template.html'),
inject: 'head'
})
可配置的值:
'true'
: 注入'false'
: 不注入'header'
: 注入头部'body'
: 注入body
底部
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script type="text/javascript" src="index.js"></script></head>
<body>
<h1>这是一个模板文件</h1>
</body>
</html>
压缩 html
webpack.config.js
添加配置
new HtmlWebpackPlugin({
title: 'html-webpack-plugin配置的title',
filename: 'admin.html',
template: path.resolve(__dirname, 'template.html'),
inject: 'head',
minify: {
collapseWhitespace: true
}
})
$ npm run build
打包后的 admin.html
<!DOCTYPE html><html><head><meta charset="utf-8"><script type="text/javascript" src="index.js"></script></head><body><h1>这是一个模板文件</h1></body></html>
可选配置
minify 的值是一个对象,具体配置项 html-minifier的配置说明
多入口的时候自定义插入的 chunk
添加 入口文件 index2.js, index3.js
// ./src/index2.js
console.log('hello index2')
// ./src/index3.js
console.log('hello index3')
更改配置,entry, output, plugin
// entry: './src/index.js',
entry: {
index1: './src/index.js',
index2: './src/index2.js',
index3: './src/index3.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
// filename: 'index.js'
filename: '[name].[chunkhash].js'
},
// 以上为最简单配置,指定了入口和输出
// 配置 webpack-dev-server
devServer: {
contentBase: path.resolve(__dirname, 'dist'), // path.join(__dirname, ''),
port: 9000,
compress: true,
open: true,
host: 'localhost',
index: 'index.html'
},
// 插件声明
plugins: [
// new HtmlWebpackPlugin() // 默认配置
new HtmlWebpackPlugin({
title: 'html-webpack-plugin配置的title',
filename: 'admin.html',
template: path.resolve(__dirname, 'template.html'),
inject: 'head',
chunks: ['index1', 'index3'],
// minify: {
// collapseWhitespace: true
// }
})
]
entry
由单个字符串改为对象声明多个入口,output
文件名使用 [name].[chunkhash]
的格式自动命名,plugins
添加 chunks
属性指定在 entry
声明的 入口文件chunk
。
$ npm run build
打包后的 /dist/admin.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script type="text/javascript" src="index1.6566a1f8bbab58d40e5e.js"></script>
<script type="text/javascript" src="index3.de308fe9191158e0939f.js"></script>
</head>
<body>
<h1>这是一个模板文件</h1>
</body>
</html>
自定义注入 chunk
的顺序
修改配置
new HtmlWebpackPlugin({
title: 'html-webpack-plugin配置的title',
filename: 'admin.html',
template: path.resolve(__dirname, 'template.html'),
inject: 'head',
chunks: ['index1', 'index3'],
chunksSortMode: function (chunk1, chunk2) {
return -1;
}
// minify: {
// collapseWhitespace: true
// }
})
$ npm run build
打包, /dist/admin.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script type="text/javascript" src="index3.de308fe9191158e0939f.js"></script><script type="text/javascript" src="index1.6566a1f8bbab58d40e5e.js"></script></head>
<body>
<h1>这是一个模板文件</h1>
</body>
</html>
chunksSortMode
可选值
none
: 不排序'auto'
: 根据chunk的 id 排序'dependency'
: 根据依赖排序'manual'
: 手工排序function
: 提供一个函数计算排序方式,会自动调用这个函数来计算排序,可以根据chunk1.names[0]
和chunk2.names[0]
对比计算出来,如果返回大于1的数,则 chunk1在前, chunk2在后,反之亦然。调试的时候可以直接在函数中console.log(chunk1, chunk2)
来调试。
生成多页面
修改配置 webpack.config.js
// 插件声明
plugins: [
// new HtmlWebpackPlugin() // 默认配置
new HtmlWebpackPlugin({
title: 'html-webpack-plugin配置的title',
filename: 'admin.html',
template: path.resolve(__dirname, 'template.html'),
inject: 'head',
chunks: ['index1', 'index3'],
chunksSortMode: function (chunk1, chunk2) {
// return -1;
return 1;
}
}),
new HtmlWebpackPlugin({
title: '第二个页面',
filename: 'index.html',
template: path.resolve(__dirname, 'template.html'),
inject: 'head',
chunks: ['index1', 'index2'],
chunksSortMode: function (chunk1, chunk2) {
return 1;
}
})
]
$ npm run build
打包,在 /dist
下生成了 index.html 和 admin.html 两个文件
/dist/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script type="text/javascript" src="index1.6566a1f8bbab58d40e5e.js"></script><script type="text/javascript" src="index2.07f73e80bd60323cd9fd.js"></script></head>
<body>
<h1>这是一个模板文件</h1>
</body>
</html>
/dist/admin.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script type="text/javascript" src="index1.6566a1f8bbab58d40e5e.js"></script><script type="text/javascript" src="index3.de308fe9191158e0939f.js"></script></head>
<body>
<h1>这是一个模板文件</h1>
</body>
</html>
本章配置文件
var path = require('path')
// 引入 html打包插件
var HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
// entry: './src/index.js',
entry: {
index1: './src/index.js',
index2: './src/index2.js',
index3: './src/index3.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
// filename: 'index.js'
filename: '[name].[chunkhash].js'
},
// 以上为最简单配置,指定了入口和输出
// 配置 webpack-dev-server
devServer: {
contentBase: path.resolve(__dirname, 'dist'), // path.join(__dirname, ''),
port: 9000,
compress: true,
open: true,
host: 'localhost',
index: 'index.html'
},
// 插件声明
plugins: [
// new HtmlWebpackPlugin() // 默认配置
new HtmlWebpackPlugin({
title: 'html-webpack-plugin配置的title',
filename: 'admin.html',
template: path.resolve(__dirname, 'template.html'),
inject: 'head',
chunks: ['index1', 'index3'],
chunksSortMode: function (chunk1, chunk2) {
// return -1;
return 1;
},
minify: {
collapseWhitespace: true
}
}),
new HtmlWebpackPlugin({
title: '第二个页面',
filename: 'index.html',
template: path.resolve(__dirname, 'template.html'),
inject: 'head',
chunks: ['index1', 'index2'],
chunksSortMode: function (chunk1, chunk2) {
return 1;
}
// minify: {
// collapseWhitespace: true
// }
})
]
}
第四章 javascript 压缩混淆
安装依赖
$ npm install --save-dev uglifyjs-webpack-plugin
或者 $ npm i -D uglifyjs-webpack-plugin
// 简写参数
修改 ./src/index.js
document.write('hello webpack')
初始化 webpack.config.js
var path = require('path')
var UglifyJsPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
entry: path.resolve(__dirname, 'index.js'),
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.min.js'
},
plugins: [
new UglifyJsPlugin()
]
}
$ npm run build
打包, /dist/index.min.js
这时已经压缩
配置
匹配上的文件才压缩
添加 index2.js
document.write('hello webpack2')
修改 webpack.config.js 中的 entry, output, plugin
var path = require('path')
var UglifyJsPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
entry: {
index: path.resolve(__dirname, 'src/index.js'),
index2: path.resolve(__dirname, 'src/index2.js')
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].min.js'
},
plugins: [
new UglifyJsPlugin({
test: /index2/i
})
]
}
$ npm run build
打包,在 dist目录下的
'index.min.js' 未被压缩
'index2.min.js' 已压缩
test
取值: RegExp | Array<RegExp>
: 正则表达式或正则匹配数组
需要压缩的文件才压缩
new UglifyJsPlugin({
test: /index2/i,
include: /index3/i
})
排除某些文件
new UglifyJsPlugin({
test: /index2/i,
include: /index3/i,
exclude: /index4/i
})
生成 sourceMap
new UglifyJsPlugin({
test: /\.js($|\?)/i,
include: /index3/,
exclude: /index4/,
sourceMap: true
})
自定义压缩细节
配置项很多,包括是否兼容ie8、是否支持es5、6、7、8等等,还可以配置压缩的各种细节,包括是否保留注释之类的,其实使用默认就差不多了,需要的时候再去配置细节,比如anuglar中如果压缩了变量名可能导致找不到注入的服务
new UglifyJsPlugin({
test: /\.js($|\?)/i,
include: /index3/,
exclude: /index4/,
sourceMap: true,
uglifyOptions: {
ie8: true,
ecma: 6,
mangle: true,
compress: true,
warnings: false
}
})
更多配置查看 webpack关于UglifyJSPlugin章节
本章配置文件
var path = require('path')
// 引入 html打包插件
var HtmlWebpackPlugin = require('html-webpack-plugin')
// 引入 js压缩混淆插件
var UglifyJsPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
// entry: './src/index.js',
entry: {
index1: './src/index.js',
index2: './src/index2.js',
index3: './src/index3.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
// filename: 'index.js'
filename: '[name].[chunkhash].js'
},
// 以上为最简单配置,指定了入口和输出
// 配置 webpack-dev-server
devServer: {
contentBase: path.resolve(__dirname, 'dist'), // path.join(__dirname, ''),
port: 9000,
compress: true,
open: true,
host: 'localhost',
index: 'index.html'
},
// 插件声明
plugins: [
// new HtmlWebpackPlugin() // 默认配置
new HtmlWebpackPlugin({
title: 'html-webpack-plugin配置的title',
filename: 'admin.html',
template: path.resolve(__dirname, 'template.html'),
inject: 'head',
chunks: ['index1', 'index3'],
chunksSortMode: function (chunk1, chunk2) {
// return -1;
return 1;
},
minify: {
collapseWhitespace: true
}
}),
new HtmlWebpackPlugin({
title: '第二个页面',
filename: 'index.html',
template: path.resolve(__dirname, 'template.html'),
inject: 'head',
chunks: ['index1', 'index2'],
chunksSortMode: function (chunk1, chunk2) {
return 1;
},
minify: {
collapseWhitespace: true
}
}),
// uglifyjs-webpack-plugin
// new UglifyJsPlugin()
new UglifyJsPlugin({
test: /\.js($|\?)/i,
include: /index3/,
exclude: /index4/,
sourceMap: true,
uglifyOptions: {
ie8: true,
ecma: 6,
mangle: true,
compress: true,
warnings: false
}
})
]
}
本文仅作为个人学习webpack的笔记,教程来自 参考文章