《前端工程化开发二》

目录

  • 五、插件plugins

  • 5.1、插件概要

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

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

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

  • 5.4、常用plugins

  • 5.4.1、用于修改行为

  • 5.4.2、用于优化

  • 5.4.3、其它

  • 六、DevServer开发服务器

  • 6.1、快速开启DevServer

  • 6.2、参数设置

  • 七、视频

  • 八、示例

  • 九、作业

五、插件plugins

5.1、插件概要

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

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

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

[
复制代码

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

ConsoleLogOnBuildWebpackPlugin.js

const pluginName = 'ConsoleLogOnBuildWebpackPlugin';

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

[
复制代码

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

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

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

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

[
复制代码

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

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;

[
复制代码

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

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

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

第一步:安装

npm i html-webpack-plugin -D

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

const HtmlWebpackPlugin=require('html-webpack-plugin');

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

plugins:[ new HtmlWebpackPlugin({参数})
]

结果

[
复制代码

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

const HtmlWebpackPlugin = require('html-webpack-plugin')

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

[
复制代码

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

参数:

title

生成页面的titile元素

filename

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

[
复制代码

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

//webpack.config.js
...
plugins: [ new HtmlWebpackPlugin({
...
filename: 'index1.html'//可带子目录'html/index1.html'
})
]

[
复制代码

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

template

模版文件路径

templateParameters

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

[
复制代码

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

//webpack.config.js
...
plugins: [ new HtmlWebpackPlugin({
...
templateParameters: {
title: 'xxxx',
favicon: './favicon/index.ico',
}
})
]

[
复制代码

](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); "复制代码")

//webpack.config.js
...
plugins: [ new HtmlWebpackPlugin({
...
hash: true })
] //html


[
复制代码

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

运行结果:

image

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

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

第一步:安装

npm i clean-webpack-plugin --save-dev

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

const CleanWebpackPlugin=require('clean-webpack-plugin');

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

plugins:[ new CleanWebpackPlugin(['./dist']), //这个一定要放在最上面,作用是先删除dist目录再创建新的dist目录。里面的参数为要删除的目录,放在一个数组里面
...
]

在文件夹里打开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); "复制代码")

[ 'dist', // removes 'dist' folder
'build/.', // removes all files in 'build' folder
'web/*.js' // removes all JavaScript files in 'web' folder
]

[
复制代码

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

Options and defaults (可选)

[
复制代码

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

{ // 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 }

[
复制代码

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

示例:

[
复制代码

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

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'})
]
}

[
复制代码

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

示例:

webpack.config03.js

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

//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]" })
]
};

[
复制代码

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

运行前:

image

运行后:

image

5.4、常用plugins

5.4.1、用于修改行为

  • define-plugin:定义环境变量
  • context-replacement-plugin:修改 require 语句在寻找文件时的默认行为。
  • ignore-plugin:用于忽略部分文件。

5.4.2、用于优化

  • commons-chunk-plugin:提取公共代码
  • extract-text-webpack-plugin:提取 JavaScript 中的 CSS 代码到单独的文件中
  • prepack-webpack-plugin:通过 Facebook 的 Prepack 优化输出的 JavaScript 代码性能
  • uglifyjs-webpack-plugin:通过 UglifyES 压缩 ES6 代码
  • webpack-parallel-uglify-plugin:多进程执行 UglifyJS 代码压缩,提升构建速度。
  • imagemin-webpack-plugin:压缩图片文件。
  • webpack-spritesmith:用插件制作雪碧图。
  • ModuleConcatenationPlugin:开启 Webpack Scope Hoisting 功能
  • dll-plugin:借鉴 DDL 的思想大幅度提升构建速度
  • hot-module-replacement-plugin:开启模块热替换功能。

5.4.3、其它

  • serviceworker-webpack-plugin:给网页应用增加离线缓存功能
  • stylelint-webpack-plugin:集成 stylelint 到项目中
  • i18n-webpack-plugin:给你的网页支持国际化。
  • provide-plugin:从环境中提供的全局变量中加载模块,而不用导入对应的文件。
  • web-webpack-plugin:方便的为单页应用输出 HTML,比 html-webpack-plugin 好用。

六、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:

npm i -D webpack-dev-server

安装成功后在项目的根目录下执行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); "复制代码")

// webpack.config.js 配置一下 devServer
devServer: {
clientLogLevel: 'warning',
historyApiFallback: true,
hot: true,
compress: true,
host: 'localhost',
port: 8080 }

[
复制代码

](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); "复制代码")

    rewrites: [
    { from: /^/subpage/, to: '/views/subpage.html' },
    {
    from: /^/helloWorld/.*$/,
    to: function() { return '/views/hello_world.html;
    }
    }
    ]
    // 从代码可以看出 url 匹配正则,匹配成功就到某个页面。
    // 并不建议将路由写在这,一般 historyApiFallback: true 就行了。

    [
    复制代码

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

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

compress (文档)

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

contentBase (文档)

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

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

[
复制代码

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

// 单目录
contentBase: path.join(__dirname, "public") // 多目录
contentBase: [path.join(__dirname, "public"), path.join(__dirname, "assets")]

[
复制代码

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

Open (文档)

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

overlay (文档)

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

overlay:{
errors:true,
warnings:false }

quiet (文档)

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

publicPath (文档)

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

[
复制代码

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

// devServer.publicPath
publicPath: "/assets/"

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

[
复制代码

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

proxy (文档)

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

[
复制代码

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

 proxy: { '/proxy': {
target: 'http://your_api_server.com',
changeOrigin: true,
pathRewrite: { '^/proxy': '' }
}

[
复制代码

](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); "复制代码")

watchOptions: {
aggregateTimeout: 300,
poll: 1000,
ignored: /node_modules/ }

[
复制代码

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

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

[
复制代码

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

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()
]
}

[
复制代码

](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》

你可能感兴趣的:(《前端工程化开发二》)