美文网首页程序员web前端技术交流
进阶篇——webpack进阶用法(二)

进阶篇——webpack进阶用法(二)

作者: 紫荆峰 | 来源:发表于2020-08-18 21:57 被阅读0次

      上一章节主要介绍了webpack的进阶篇中的自动清理构建、补齐css前缀、静态资源内联。这一节主要介绍多页面应用打包、使用sourcemap、提取页面公共资源。

    1.多页面应用打包通用方案

    (1)什么是多页面应用
    QQ截图20200815160815.png
    优势:①每个页面之间都是解耦的;②对于系统的SEO更加友好
    (2)打包思路
    QQ截图20200815161142.png
    上面图是不是很熟悉☺,我们在基础篇-webpack基础用法(三)---html文件压缩里讲过,每个入口文件对应一个html-webpack-plugin。而且entry都是我们配置好的,每增加一个页面我们就要增加一个entry和配置一个html-webpack-plugin,显得过于繁琐,不太友好,有没有更加通用化的方案呢?如下:
    QQ截图20200815162029.png
    就是动态获取目录文件,使用程序思维自动配置好文件。已上图为例,我们在打包之前必须预定好文件必须放在src目录下面,如:index.js、search.js
    npm install glob -D
    代码如下
    const glob = require('glob');
    const path = require('path');
    
    // 设置多页面打包
    const setMPA = () => {
        const entry = {};
        const htmlWebpackPlugins = [];
    
        const entryFiles = glob.sync(path.join(__dirname, './src/*/index.js'));
    
        Object.keys(entryFiles)
            .map((index) => {
                const entryFile = entryFiles[index];
    
                const match = entryFile.match(/src\/(.*)\/index\.js/);
                const pageName = match && match[1];
    
                entry[pageName] = entryFile;
                htmlWebpackPlugins.push(
                    new HtmlWebpackPlugin({
                        template: path.join(__dirname, `src/${pageName}/index.html`),
                        filename: `${pageName}.html`,
                        chunks: [pageName],
                        inject: true,
                        minify: {
                            html5: true,
                            collapseWhitespace: true,
                            preserveLineBreaks: false,
                            minifyCSS: true,
                            minifyJS: true,
                            removeComments: false
                        }
                    }),
                );
            })
    
        return {
            entry,
            htmlWebpackPlugins
        }
    }
    
    module.exports = {
        entry: entry,
        ...
        
        plugins: [
            new MiniCssExtractPlugin({
                filename: '[name]_[contenthash:8].css'
            }),
            new OptimizeCSSAssetsPlugin({
                assetNameRegExp: /\.css$/g,
                cssProcessor: require('cssnano')
            }),
            
            new CleanWebpackPlugin()
        ].concat(htmlWebpackPlugins)
    };
    

    这样我们每次添加页面时,就不用了手动去修改webpack配置了。

    2.使用sourceMap

    我们在使用webpack进行打包的时候,它会把我们的代码打包成bundle文件,但是在打包的过程中可能会出现错误,我们会发现控制台会把一大串的错误代码打印出来,但是不会定位到具体的错误文件,这时就要轮到我们的sourcemap登场了,具体作用如下

    QQ截图20200817202604.png
    (1)关键字
    QQ截图20200817202757.png
    (2)类型
    QQ截图20200817203040.png
    ① eval类型的sourcemap
    QQ截图20200817203605.png

    npm run build打包之后,我们打开dist文件下的js文件如下


    QQ截图20200817203736.png
    QQ截图20200817204019.png

    我们可以看到,eval把我们的js文件打包之后用eval()包裹了起来,后面用sourceURL制定文件路径。

    ② source map类型
    QQ截图20200817204301.png

    导报之后


    QQ截图20200817204456.png

    可以看到,它把我们的js文件进行了分离,生成了一个js文件一个.map文件。我们打开js文件,拉倒最后一行,会出现如下一句话


    QQ截图20200817204718.png
    这表示,该js文件要使用的是哪一个map文件。
    ③ inline-source-map类型
    QQ截图20200817204930.png
    打包之后
    QQ截图20200817205053.png
    可以看到,打包之后的dist文件目录下已经没有.map文件了,那么它跑到哪里去了呢?
    我们打开js文件,拉倒最后一行
    QQ截图20200817205335.png
    直接使用sourceMappingURL给引进来了,但是我们也会发现这个js也会变大许多。
    ④ 开发调试

    打开webpack.dev.js文件,如下代码

    'use strict';
    
    const glob = require('glob');
    const path = require('path');
    const webpack = require('webpack');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const { CleanWebpackPlugin } = require('clean-webpack-plugin');
    
    // 设置多页面打包
    const setMPA = () => {
        const entry = {};
        const htmlWebpackPlugins = [];
    
        const entryFiles = glob.sync(path.join(__dirname, './src/*/index.js'));
    
        Object.keys(entryFiles)
            .map((index) => {
                const entryFile = entryFiles[index];
    
                const match = entryFile.match(/src\/(.*)\/index\.js/);
                const pageName = match && match[1];
    
                entry[pageName] = entryFile;
                htmlWebpackPlugins.push(
                    new HtmlWebpackPlugin({
                        template: path.join(__dirname, `src/${pageName}/index.html`),
                        filename: `${pageName}.html`,
                        chunks: [pageName],
                        inject: true,
                        minify: {
                            html5: true,
                            collapseWhitespace: true,
                            preserveLineBreaks: false,
                            minifyCSS: true,
                            minifyJS: true,
                            removeComments: false
                        }
                    }),
                );
            })
    
        return {
            entry,
            htmlWebpackPlugins
        }
    }
    
    const { entry, htmlWebpackPlugins } = setMPA();
    
    module.exports = {
        entry: entry,
        output: {
            path: path.join(__dirname, 'dist'),
            filename:  '[name].js'
        },
        mode: 'development',
        module: {
            rules: [
                {
                    test: /.js$/,
                    use: 'babel-loader'
                },
                {
                    test: /.css$/,
                    use: [
                        'style-loader',
                        'css-loader'
                    ]
                },
                {
                    test: /.less$/,
                    use: [
                        'style-loader',
                        'css-loader',
                        'less-loader'
                    ]
                },
                {
                    test: /.(png|jpg|gif|jpeg)$/,
                    use: [
                        {
                            loader: 'url-loader',
                            options: {
                                limit: 10240
                            }
                        }
                    ]
                },
                {
                    test: /.(woff|woff2|eot|ttf|otf)$/,
                    use: 'file-loader'
                }
            ]
        },
        plugins: [
            new webpack.HotModuleReplacementPlugin(),
            new CleanWebpackPlugin()
        ].concat(htmlWebpackPlugins),
        devServer: {
            contentBase: './dist',   // 打印目录下的信息
            hot: true     // 开启热更新
        },
        devtool: 'source-map'
    };
    

    运行
    npm run dev

    QQ截图20200817210658.png
    可以看到这样调试的话,就能看到源代码了,而且非常方便调试。
    ⑤ cheap-source-map类型
    QQ截图20200817211017.png

    在js文件下故意写错一行代码,如下

    QQ截图20200817211051.png
    QQ截图20200817211408.png
    可以看到,cheap-source-map帮我们定位了错误在哪一个文件哪一行,就会方便开发调试了。

    3.提取页面公共资源

    我们在项目开发中,可能各个页面中使用同一套的资源库,或者各个页面也有可能使用相同的css样式,如果我们在打包的时候,就会把这些页面中的资源都会打包一份,这样就会降低打包速度、浪费打包资源、是项目的整体资源过大等等,因此我们需要将这些相同资源提取到一个公共文件中,降低体积。这里我们一react为例。

    (1)基础库分离
    QQ截图20200818203456.png
    entry:可以使第三链接,也可以是本地资源地址
    (2)利⽤ SplitChunksPlugin 进⾏公共脚本分离
    QQ截图20200818203636.png
    minSize(字节):抽离的公共包最小的大小;
    maxSize(字节):抽离的公共包最大的大小;
    minChunks:表示一个方法在项目中使用的最低次数,如果设置成2,那就表示这个方法在项目最低使用2次,webpack才会将这个方法提取成公共方法;
    maxAsyncRequests:浏览器每次请求一步资源的次数。比如浏览器在异步请求一个js时的次数超过指定的值时,就会提取成公共资源;
    (3)利⽤ SplitChunksPlugin 分离基础包
    QQ截图20200818204824.png
    (4)利⽤ SplitChunksPlugin 分离⻚⾯公共⽂件
    QQ截图20200818205004.png
    (5)实战演练
    ① html-webpack-externals-plugin

    安装 html-webpack-externals-plugin插件
    npm install html-webpack-externals-plugin -D

    QQ截图20200818210449.png
    在html中引入react、react-dom资源
    QQ截图20200818211549.png

    构建一下


    QQ截图20200818210602.png

    对比以前的打包方式,发现体积差不多小了100K左右。

    ② SplitChunksPlugin分离
    QQ截图20200818212009.png

    构建如下


    QQ截图20200818212133.png
    ③ SplitChunksPlugin分离⻚⾯公共⽂件

    我们在项目的根目录下创建一个文件,export一个函数,在不同的页面分别引入一下,配置一下webpack,如下


    QQ截图20200818214927.png

    构建一下项目


    QQ截图20200818215026.png
    会把公共方法放在了common.js文件里面

    总结

    主要学习了多页面应用打包通用方案、使用sourceMap、提取页面公共资源这三个方面的指示点,下一节学习tree shaking、scope hoisting、动态分割和import等方法。
    来源极客时间

    相关文章

      网友评论

        本文标题:进阶篇——webpack进阶用法(二)

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