美文网首页前端工程化和模块化
《前端工程化开发二》

《前端工程化开发二》

作者: 前端驿站 | 来源:发表于2020-03-22 21:08 被阅读0次

    目录

    五、插件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》

    相关文章

      网友评论

        本文标题:《前端工程化开发二》

        本文链接:https://www.haomeiwen.com/subject/qiqbyhtx.html