《前端工程化开发二》

目录

五、插件plugins

5.1、插件概要

Plugin 是用来扩展 Webpack 功能的,通过在构建流程里注入钩子实现,它给 Webpack 带来了很大的灵活性。

插件是 webpack 的支柱功能。webpack 自身也是构建于,你在 webpack 配置中用到的相同的插件系统之上!插件目的在于解决 loader 无法实现的其他事。

webpack 插件是一个具有 apply 属性的 JavaScript 对象。apply 属性会被 webpack compiler 调用,并且 compiler 对象可在整个编译生命周期访问。

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">ConsoleLogOnBuildWebpackPlugin.js

const pluginName = 'ConsoleLogOnBuildWebpackPlugin';

class ConsoleLogOnBuildWebpackPlugin {
apply(compiler) {
compiler.hooks.run.tap(pluginName, compilation => {
console.log("webpack 构建过程开始!");
});
}
}</pre>

[
复制代码

](javascript:void(0); "复制代码")

compiler hook 的 tap 方法的第一个参数,应该是驼峰式命名的插件名称。建议为此使用一个常量,以便它可以在所有 hook 中复用。

由于插件可以带参数/选项,你必须在 webpack 配置中,向 plugins 属性传入 new 实例。

根据你的 webpack 用法,这里有多种方式使用插件。

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin'); //通过 npm 安装
const webpack = require('webpack'); //访问内置的插件
const path = require('path');

const config = {
entry: './path/to/my/entry/file.js',
output: {
filename: 'my-first-webpack.bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /.(js|jsx)$/,
use: 'babel-loader' }
]
},
plugins: [ new webpack.optimize.UglifyJsPlugin(), new HtmlWebpackPlugin({template: './src/index.html'})
]
};

module.exports = config;</pre>

[
复制代码

](javascript:void(0); "复制代码")

5.1、HTML Webpack Plugin(创建HTML插件)

该个插件的作用是用来自动生成html页面,既可以生成单个页面又可以生成多个页面,并且在生成前可以给它一些的配置参数,它会按照你想要的生成方式去生成页面。

第一步:安装

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">npm i html-webpack-plugin -D</pre>

第二步:在webpack.config.js里引入模块

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">const HtmlWebpackPlugin=require('html-webpack-plugin');</pre>

第三步:在webpack.config.js中的plugins对象里new一个实例

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">plugins:[ new HtmlWebpackPlugin({参数})
]</pre>

结果

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
entry: 'index.js',
output: {
path: __dirname + '/dist',
filename: 'index_bundle.js' },
plugins: [ new HtmlWebpackPlugin()
]
}</pre>

[
复制代码

](javascript:void(0); "复制代码")

参数:

title

生成页面的titile元素

filename

生成的html文件的文件名。默认index.html,可以直接配置带有子目录

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">//webpack.config.js
...
plugins: [ new HtmlWebpackPlugin({
...
filename: 'index1.html'//可带子目录'html/index1.html'
})
]</pre>

[
复制代码

](javascript:void(0); "复制代码")

template

模版文件路径

templateParameters

{Boolean|Object|Function} 允许覆盖模板中使用的参数

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">//webpack.config.js
...
plugins: [ new HtmlWebpackPlugin({
...
templateParameters: {
title: 'xxxx',
favicon: './favicon/index.ico',
}
})
]</pre>

[
复制代码

](javascript:void(0); "复制代码")

inject

插入的script插入的位置,四个可选值:
true: 默认值,script标签位于html文件的body底部
body: 同true
head: script标签位于html文件的head标签内
false: 不插入生成的js文件,只是生成的html文件

favicon

为生成的html文件生成一个favicon,属性值是路径

minify

html文件进行压缩。属性值是false或者压缩选项值。默认false不对html文件进行压缩。
html-webpack-plugin中集成的html-minifier,生成模板文件压缩配置,有很多配置项,这些配置项就是minify的压缩选项值。

hash

给生成的js文件尾部添加一个hash值。这个hash值是本次webpack编译的hash值。默认false;

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">//webpack.config.js
...
plugins: [ new HtmlWebpackPlugin({
...
hash: true })
] //html
<script type="text/javascript" src="bundle.js?59a5ed17040d94df87fe">
//59a5ed17040d94df87fe是本次webpack编译的hash值</pre>

[
复制代码

](javascript:void(0); "复制代码")

cache

Boolean类型。只在文件被修改的时候才生成一个新文件。默认值true

showErrors

Boolean类型。错误信息是否写入html文件。默认true

chunks

html文件中引用哪些js文件,用于多入口文件时。不指定chunks时,所有文件都引用

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">//webpack.config.js
entry: {
index1: path.resolve(__dirname, './index1.js'),
index2: path.resolve(__dirname, './index2.js'),
index3: path.resolve(__dirname, './index3.js')
}
...
plugins: [ new HtmlWebpackPlugin({
...
chunks: [index1, index2]//html文件中只引入index1.js, index2.js
})
]</pre>

[
复制代码

](javascript:void(0); "复制代码")

excludeChunks

与chunks相反,html文件不引用哪些js文件

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">//webpack.config.js
entry: {
index1: path.resolve(__dirname, './index1.js'),
index2: path.resolve(__dirname, './index2.js'),
index3: path.resolve(__dirname, './index3.js')
}
...
plugins: [ new HtmlWebpackPlugin({
...
excludeChunks: [index3.js]//html文件中不引入index3.js
})
]</pre>

[
复制代码

](javascript:void(0); "复制代码")

chunksSortMode

控制script标签的引用顺序。默认五个选项:
none: 无序
auto: 默认值, 按插件内置的排序方式
dependency: 根据不同文件的依赖关系排序
manual: chunks按引入的顺序排序, 即属性chunks的顺序
{Function}: 指定具体的排序规则

xhtml

Boolean类型,默认false, true时以兼容xhtml的模式引用文件

示例:

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">plugins:[ new HtmlWebpackPlugin({
title:'Hello app', /这个值对应html里的title/ template:'./src/template.html', //模板文件地址
filename:'test1.html', //文件名,默认为index.html(路径相对于output.path的值)
inject:true, //script标签的位置,true/body为在</body>标签前,head为在<head>里,false表示页面不引入js文件
hash:true, //是否为引入的js文件添加hash值
chunks:['one'], //页面里要引入的js文件,值对应的是entry里的key。省略参数会把entry里所有文件都引入
//excludeChunks:['one'],//页面里不能引入的js文件,与chunks刚好相反
minify:{ //html-webpack-plugin内部集成了html-minifier
collapseWhitespace:true, //压缩空格
removeAttributeQuotes:true, //移除引号
removeComments:true, //移除注释
},
}), //生成两个文件,分别引入两个js文件(现在是一个文件里引入了两个js)
new HtmlWebpackPlugin({
title:'kaivon',
template:'./src/template.html',
hash:true,
filename:'test2.html',
chunks:['two']
})
]</pre>

[
复制代码

](javascript:void(0); "复制代码")

示例1:

webpack.config03.js配置文件

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">//webpack配置文件

//导入用于生成html的插件
const HtmlWebpackPlugin=require("html-webpack-plugin"); //依赖node中的path模块
var path=require('path'); //定义一个默认模块对象
module.exports={
entry:{app01:"./src/app03.js"}, //设置输出结果
output: { //路径,将相对路径转绝对路径
path:path.resolve(__dirname,'dist'), //文件,[name]是模块名称,占位
filename: "[hash:8].bundle.js" },
module: {
},
plugins: [ //创建一个插件对象,并指定参数
new HtmlWebpackPlugin({ //指定生成的文件路径与名称
filename:"../app03.html", //标题
title:"Hello App03!" })
]
};</pre>

[
复制代码

](javascript:void(0); "复制代码")

arc/app03.js

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">alert("Hello App03!");</pre>

打包结果:

image

运行:

image

示例2:

webpack.config03.js配置文件

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">//webpack配置文件

//导入用于生成html的插件
const HtmlWebpackPlugin=require("html-webpack-plugin"); //依赖node中的path模块
var path=require('path'); //定义一个默认模块对象
module.exports={
entry:{app01:"./src/app03.js"}, //设置输出结果
output: { //路径,将相对路径转绝对路径
path:path.resolve(__dirname,'dist'), //文件,[name]是模块名称,占位
filename: "[hash:8].bundle.js" },
module: {
},
plugins: [ //创建一个插件对象,并指定参数
new HtmlWebpackPlugin({ //指定生成的文件路径与名称
filename:"../app03.html", //标题
title:"Hello App03!", //指定模板
template:"./templates/tmpl03.html", //模板参数,允许覆盖templates中的参数
templateParameters:{
content:"Hello templateParameters!", //重写title
title:"Hello App03 title!",
key:"value" },
minify:{
removeComments:true, //移除注释
collapseWhitespace:true, //折叠空格
//更新请参数https://github.com/kangax/html-minifier#options-quick-reference
}
})
]
};</pre>

[
复制代码

](javascript:void(0); "复制代码")

/templates/tmpl03.html 模板文件

image

View Code

生成结果:

image

5.2、Mini-css-extract-plugin(单独提取CSS插件)

将CSS提取为独立的文件的插件,对每个包含css的js文件都会创建一个CSS文件,支持按需加载css和sourceMap

默认情况下css是被js注入的一段style,如下所示:

image

只能用在webpack4中,对比另一个插件 extract-text-webpack-plugin特点:

  • 异步加载
  • 不重复编译,性能更好
  • 更容易使用
  • 只针对CSS

目前缺失功能,HMR(热模块替换)。

image

HMR解释

安装:

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">npm install --save-dev mini-css-extract-plugin</pre>

使用:

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
plugins: [ new MiniCssExtractPlugin({ // 类似 webpackOptions.output里面的配置 可以忽略
filename: '[name].css',
chunkFilename: '[id].css',
}),
],
module: {
rules: [
{
test: /.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: { // 这里可以指定一个 publicPath
// 默认使用 webpackOptions.output中的publicPath
publicPath: '../' },
}, 'css-loader',
],
}
]
}
}</pre>

[
复制代码

](javascript:void(0); "复制代码")

高级配置:

这个插件应该只用在 production 配置中,并且在loaders链中不使用 style-loader, 特别是在开发中使用HMR,因为这个插件暂时不支持HMR

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const devMode = process.env.NODE_ENV !== 'production';

module.exports = {
plugins: [ new MiniCssExtractPlugin({
filename: devMode ? '[name].css' : '[name].[hash].css',
chunkFilename: devMode ? '[id].css' : '[id].[hash].css',
})
],
module: {
rules: [
{
test: /.(sa|sc|c)ss$/,
use: [
devMode ? 'style-loader' : MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader',
],
}
]
}
}</pre>

[
复制代码

](javascript:void(0); "复制代码")

示例:

webpack.config03.js

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">//webpack配置文件

//导入用于生成html的插件
const HtmlWebpackPlugin=require("html-webpack-plugin"); //导入用于提取css的插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); //依赖node中的path模块
var path=require('path'); //定义一个默认模块对象
module.exports={
entry:{app01:"./src/app03.js"}, //设置输出结果
output: { //路径,将相对路径转绝对路径
path:path.resolve(_dirname,'dist'), //文件,[name]是模块名称,占位
filename: "[hash:8].bundle.js" },
module: {
rules: [
{
test: /.scss$/,
use: [{
loader:MiniCssExtractPlugin.loader //提取css并link
}, {
loader: "css-loader" // 将 CSS 转化成 CommonJS 模块
}, {
loader: "sass-loader" // 将 Scss 编译成 CSS
}]
}
]
},
plugins: [ //创建一个插件对象,并指定参数
new HtmlWebpackPlugin({ //指定生成的文件路径与名称
filename:"../app03.html", //标题
title:"Hello App03!", //指定模板
template:"./templates/tmpl03.html", //模板参数,允许覆盖templates中的参数
templateParameters:{
content:"Hello templateParameters!", //重写title
title:"Hello App03 title!",
key:"value" },
minify:{
removeComments:true, //移除注释
collapseWhitespace:true, //折叠空格
//更新请参数https://github.com/kangax/html-minifier#options-quick-reference
}
}), //创建一个用于提取css的插件对象
new MiniCssExtractPlugin({
filename:"[name]
[hash:10].css",
chunkFilename:"[id]" })
]
};</pre>

[
复制代码

](javascript:void(0); "复制代码")

src/app03.js

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">import '../css/baseScss.scss';

alert("Hello App03!");</pre>

打包生成的结果

[
复制代码
](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);"><!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Hello App03 title!</title>
<link href="dist/app01_1b7c11aa92.css" rel="stylesheet">
</head>
<body><h2>Hello templateParameters!</h2>
<script type="text/javascript" src="dist/1b7c11aa.bundle.js"></script>
</body>
</html></pre>

[
复制代码

](javascript:void(0); "复制代码")

运行结果:

image

5.3、clean-webpack-plugin(删除或清理构建目录)

在用HtmlWebpackPlugin的时候时需要把dist目录删掉再去看生成的文件,clean-webpack-plugin这个插件就可以做这件事情

第一步:安装

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">npm i clean-webpack-plugin --save-dev</pre>

第二步:在webpack.config.js里引入模块

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">const CleanWebpackPlugin=require('clean-webpack-plugin');</pre>

第三步:在plugins的最前面创建清理对象

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">plugins:[ new CleanWebpackPlugin(['./dist']), //这个一定要放在最上面,作用是先删除dist目录再创建新的dist目录。里面的参数为要删除的目录,放在一个数组里面
...
]</pre>

在文件夹里打开dist所在的目录,并在终端里再次执行命令webpack后,会看到dist目录先被删除后又被创建。

关于clean-webpack-plugin插件的所有配置参数请参考:https://www.npmjs.com/package/clean-webpack-plugin

该插件有两个参数:

Paths ( 必须)

An [array] of string paths to clean

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">[ 'dist', // removes 'dist' folder
'build/.', // removes all files in 'build' folder
'web/*.js' // removes all JavaScript files in 'web' folder
]</pre>

[
复制代码

](javascript:void(0); "复制代码")

Options and defaults (可选)

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">{ // Absolute path to your webpack root folder (paths appended to this)
// Default: root of your package
root: __dirname, // Write logs to console.
verbose: true, // Use boolean "true" to test/emulate delete. (will not remove files).
// Default: false - remove files
dry: false, // If true, remove files on recompile.
// Default: false
watch: false, // Instead of removing whole path recursively,
// remove all path's content with exclusion of provided immediate children.
// Good for not removing shared files from build directories.
exclude: [ 'files', 'to', 'ignore' ], // allow the plugin to clean folders outside of the webpack root.
// Default: false - don't allow clean folder outside of the webpack root
allowExternal: false

// perform clean just before files are emitted to the output dir
// Default: false
beforeEmit: false }</pre>

[
复制代码

](javascript:void(0); "复制代码")

示例:

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">const CleanWebpackPlugin = require('clean-webpack-plugin'); //installed via npm
const HtmlWebpackPlugin = require('html-webpack-plugin'); //installed via npm
const webpack = require('webpack'); //to access built-in plugins
const path = require('path'); // the path(s) that should be cleaned
let pathsToClean = [ 'dist', 'build' ] // the clean options to use
let cleanOptions = {
root: '/full/webpack/root/path',
exclude: ['shared.js'],
verbose: true,
dry: false } // sample WebPack config
const webpackConfig = {
entry: './path/to/my/entry/file.js',
output: {
filename: 'my-first-webpack.bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /.(js|jsx)$/,
loader: 'babel-loader' }
]
},
plugins: [ new CleanWebpackPlugin(pathsToClean, cleanOptions), new webpack.optimize.UglifyJsPlugin(), new HtmlWebpackPlugin({template: './src/index.html'})
]
}</pre>

[
复制代码

](javascript:void(0); "复制代码")

示例:

webpack.config03.js

[
复制代码
](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">//webpack配置文件

//导入用于理清目录的插件
const CleanWebpackPlugin=require('clean-webpack-plugin'); //导入用于生成html的插件
const HtmlWebpackPlugin=require("html-webpack-plugin"); //导入用于提取css的插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); //依赖node中的path模块
var path=require('path'); //定义一个默认模块对象
module.exports={
entry:{app01:"./src/app03.js"}, //设置输出结果
output: { //路径,将相对路径转绝对路径
path:path.resolve(_dirname,'dist'), //文件,[name]是模块名称,占位
filename: "[hash:8].bundle.js" },
module: {
rules: [
{
test: /.scss$/,
use: [{
loader:MiniCssExtractPlugin.loader //提取css并link
}, {
loader: "css-loader" // 将 CSS 转化成 CommonJS 模块
}, {
loader: "sass-loader" // 将 Scss 编译成 CSS
}]
}
]
},
plugins: [ //创建一个清理插件,参数一为目标,如路径,参数二为选项
new CleanWebpackPlugin(['dist'],{dry:false}), //创建一个插件对象,并指定参数
new HtmlWebpackPlugin({ //指定生成的文件路径与名称
filename:"../app03.html", //标题
title:"Hello App03!", //指定模板
template:"./templates/tmpl03.html", //模板参数,允许覆盖templates中的参数
templateParameters:{
content:"Hello templateParameters!", //重写title
title:"Hello App03 title!",
key:"value" },
minify:{
removeComments:true, //移除注释
collapseWhitespace:true, //折叠空格
//更新请参数https://github.com/kangax/html-minifier#options-quick-reference
}
}), //创建一个用于提取css的插件对象
new MiniCssExtractPlugin({
filename:"[name]
[hash:10].css",
chunkFilename:"[id]" })
]
};</pre>

[
复制代码

](javascript:void(0); "复制代码")

运行前:

image

运行后:

image

5.4、常用plugins

5.4.1、用于修改行为

5.4.2、用于优化

5.4.3、其它

六、DevServer开发服务器

webpack-dev-server就是一个基于Node.js和webpack的一个简易服务器。它在服务器端使用webpack-dev-middleware进行webpack构建打包;并在客户端注入一份runtime,用于接受服务器端的构建打包后信息。

在实际开发中我们可能会需要完成如下功能:

  1. 提供 HTTP 服务而不是使用本地文件预览;
  2. 监听文件的变化并自动刷新网页,做到实时预览;
  3. 支持 Source Map,以方便调试。

Webpack 原生支持上述第2、3点内容,再结合官方提供的开发工具 DevServer 也可以很方便地做到第1点。 DevServer 会启动一个 HTTP 服务器用于服务网页请求,同时会帮助启动 Webpack ,并接收 Webpack 发出的文件更变信号,通过 WebSocket 协议自动刷新网页做到实时预览。

6.1、快速开启DevServer

安装 DevServer:

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">npm i -D webpack-dev-server</pre>

安装成功后在项目的根目录下执行webpack-dev-server 命令, DevServer 服务器就启动了,这时你会看到控制台有一串日志输出:

Project is running at http://localhost:8080/

webpack output is served from /

image

现在就可以直接访问了

image

这意味着 DevServer 启动的 HTTP 服务器监听在 http://localhost:8080/ ,DevServer 启动后会一直驻留在后台保持运行,访问这个网址你就能获取项目根目录下的 index.html。

注意:

1、此时可能会提示webpack-dev-server不是内部命令,解决办法为在全局再次安装一下webpack-dev-server模块,或者在package.json里的scripts里加上"dev": "webpack-dev-server",然后执行命令npm run dev

2、并没有通过webpack命令生成一个dist目录,然后在浏览器里输入地址http://localhost:8080/后,页面会正常显示。这个原因是devServer会将webpack构建出的文件保存到内存里,不需要打包生成就能预览

6.2、参数设置

在webpack.config.js中可以根据需要配置dev-server满足你更多的需求。

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">// webpack.config.js 配置一下 devServer
devServer: {
clientLogLevel: 'warning',
historyApiFallback: true,
hot: true,
compress: true,
host: 'localhost',
port: 8080 }</pre>

[
复制代码

](javascript:void(0); "复制代码")

Hot文档

  • 热模块更新作用。即修改或模块后,保存会自动更新,页面不用刷新呈现最新的效果。
  • 这不是和 webpack.HotModuleReplacementPlugin (HMR) 这个插件不是一样功能吗?是的,不过请注意了,***HMR* 这个插件是真正实现热模块更新的**。而 devServer 里配置了 hot: true , webpack会自动添加 HMR 插件。所以模块热更新最终还是 HMR 这个插件起的作用。

host文档

  • 写主机名的。默认 localhost

port文档

  • 端口号。默认 8080

historyApiFallback文档

  • 如果为 true ,页面出错不会弹出 404 页面。

  • 如果为 {...} , 看看一般里面有什么。

    • rewrites

    [
    复制代码

    ](javascript:void(0); "复制代码")

    <pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">rewrites: [
    { from: /^/subpage/, to: '/views/subpage.html' },
    {
    from: /^/helloWorld/.*$/,
    to: function() { return '/views/hello_world.html;
    }
    }
    ]
    // 从代码可以看出 url 匹配正则,匹配成功就到某个页面。
    // 并不建议将路由写在这,一般 historyApiFallback: true 就行了。</pre>

    [
    复制代码

    ](javascript:void(0); "复制代码")

    • verbose:如果 true ,则激活日志记录。
    • disableDotRule: 禁止 url 带小数点 .

compress (文档)

  • 如果为 true ,开启虚拟服务器时,为你的代码进行压缩。加快开发流程和优化的作用。

contentBase文档

  • 你要提供哪里的内容给虚拟服务器用。这里最好填 绝对路径

  • 默认情况下,它将使用您当前的工作目录来提供内容。

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">// 单目录
contentBase: path.join(__dirname, "public") // 多目录
contentBase: [path.join(__dirname, "public"), path.join(__dirname, "assets")]</pre>

[
复制代码

](javascript:void(0); "复制代码")

Open文档

  • true,则自动打开浏览器。

overlay (文档)

  • 如果为 true ,在浏览器上全屏显示编译的errors或warnings。默认 false (关闭)
  • 如果你只想看 error ,不想看 warning

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">overlay:{
errors:true,
warnings:false }</pre>

quiet文档

  • true,则终端输出的只有初始启动信息。 webpack 的警告和错误是不输出到终端的。

publicPath文档

  • 配置了 publicPath后, *url* = '主机名' + '*publicPath*配置的' + '原来的*url.path*'。这个其实与 output.publicPath 用法大同小异。
  • output.publicPath 是作用于 js, css, img 。而 devServer.publicPath 则作用于请求路径上的。

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">// devServer.publicPath
publicPath: "/assets/"

// 原本路径 --> 变换后的路径
http://localhost:8080/app.js --> http://localhost:8080/assets/app.js</pre>

[
复制代码

](javascript:void(0); "复制代码")

proxy (文档)

  • 当您有一个单独的API后端开发服务器,并且想要在同一个域上发送API请求时,则代理这些 url 。看例子好理解。

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);"> proxy: { '/proxy': {
target: 'http://your_api_server.com',
changeOrigin: true,
pathRewrite: { '^/proxy': '' }
}</pre>

[
复制代码

](javascript:void(0); "复制代码")

  1. 假设你主机名为 localhost:8080 , 请求 APIurlhttp://your_api_server.com/user/list
  2. '/proxy':如果点击某个按钮,触发请求 API 事件,这时请求 urlhttp://localhost:8080**/proxy**/user/list
  3. changeOrigin:如果 true ,那么 http://localhost:8080/proxy/user/list 变为 http://your_api_server.com/proxy/user/list 。但还不是我们要的 url
  4. pathRewrite:重写路径。匹配 /proxy ,然后变为'' ,那么 url 最终为 http://your_api_server.com/user/list

watchOptions文档

  • 一组自定义的监听模式,用来监听文件是否被改动过。

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">watchOptions: {
aggregateTimeout: 300,
poll: 1000,
ignored: /node_modules/ }</pre>

[
复制代码

](javascript:void(0); "复制代码")

  1. aggregateTimeout:一旦第一个文件改变,在重建之前添加一个延迟。填以毫秒为单位的数字。
  2. ignored:观察许多文件系统会导致大量的CPU或内存使用量。可以排除一个巨大的文件夹。
  3. poll:填以毫秒为单位的数字。每隔(你设定的)多少时间查一下有没有文件改动过。不想启用也可以填false

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; font-family: "microsoft yahei" !important; white-space: pre-wrap; overflow-wrap: break-word; font-size: 16px !important; background: rgb(255, 255, 255);">var path = require("path"); var webpack = require("webpack");
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode:"development",
entry:{
app:"./src/js/main.js" },
output:{
filename: "bundle.js",
path:path.resolve(__dirname,"../dist"), //path.resolve是nodejs里的方法,具体看nodejs api
},
devServer:{
contentBase:false, //我这里没有设置contentBase,contentBase必须指向存在的bundle.js文件所在目录,
//因为这里是开发模式,所以dist目录并不存在,所以用false.
host:'localhost',
port:'8888',
inline:true,//webpack官方推荐
watchOptions: {
aggregateTimeout: 2000,//浏览器延迟多少秒更新
poll: 1000//每秒检查一次变动
},
compress:true,//一切服务都启用gzip 压缩
historyApiFallback:true,//找不到页面默认跳index.html
hot:true,//启动热更新,必须搭配new webpack.HotModuleReplacementPlugin()插件
open:true,
},
plugins: [ new webpack.HotModuleReplacementPlugin(), new HtmlWebpackPlugin({
template:"index.html",
title:'index',
inject: true }), // new webpack.NamedModulesPlugin(),
// HMR shows correct file names in console on update.
// new webpack.NoEmitOnErrorsPlugin()
]
} </pre>

[
复制代码

](javascript:void(0); "复制代码")

示例:

配置文件:

image

View Code

运行结果:


image

七、视频

https://www.bilibili.com/video/av37008594/

八、示例

https://git.dev.tencent.com/zhangguo5/WebPackDemo.git

九、作业

(1)、创建一个项目,项目中使用ES6的模块功能与箭头函数,使用babel-loader转译成兼容IE8的前端输出。

本文转载于张果大神的《10分钟学会前端工程化webpack4.0》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容