最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 偷学VueCli和CRA脚手架,入门webpack配置工程师

    正文概述 掘金(楼下的小黑)   2021-01-31   711

    背景

    目前前端工程化很好,前端工程化在构建方面的核心毫无疑问是webpackwebpack工程师,是每个前端工程师都要有的头衔(狗头保命),为了学习webpack,笔者看完了webpack中文网又查阅很多webpack的文章和VueCliCRA脚手架,发掘目前基础webpack配置,希望积累webpack的最佳实践,抵御不住webpack5的诱惑,新增了本项目从webpack4(master分支)升级到webpack5(webpackV5分支)的艰难流程,最终的代码地址

    安装webpack

    # 安装4最新版本
    yarn add webpack@"^4.0.0"
    

    加上配置文件 webpack.config.js

    module.exports = {
        entry: './src/index.js'
        // 开发模式
        mode:'development',
        // 单独提取source-map,输出后的js更可读
        devtool : 'source-map'
    };
    

    添加运行命令

    package.json

    {
      "name": "webpack4-best-pratice",
      "version": "1.0.0",
      "main": "index.js",
      "license": "MIT",
      "scripts": {
         // 添加dev命令
        "dev": "webpack"
      },
      "dependencies": {
        "webpack": "^4.0.0"
      }
    }
    

    添加src目录并运行

    yarn dev
    

    偷学VueCli和CRA脚手架,入门webpack配置工程师

    javascript代码环境降级

    babel通过编译es6到es5实现了开发中使用es6代码部署中又不用考虑浏览器兼容

    安装babel

    # @babel/core babel 转换器核心包
    # @babel/preset-env babel转化配置包
    # babel-loader baberl的webpack插件
    yarn add babel-loader @babel/core @babel/preset-env
    

    使用webpack编译代码

    在src/index.js新增

    const a = 1
    

    执行dev命令

    yarn dev
    

    偷学VueCli和CRA脚手架,入门webpack配置工程师

    查看输出结果发现我们的const没有被编译成es5,接下来我们来解决这个问题

    配置babel转译语法

    新增babel.config.js

    module.exports = {
        // 引入编译选项
        presets: [
            [
                '@babel/preset-env'
            ],
        ],
    };
    

    配置webpack对js文件使用babel编译

    module.exports = {
        // .... 新增module字段
        module: {
            rules: [
              { 
                // 匹配.js文件
                test: /\.js$/,
                // 排除node_modules提升编译效率
                exclude: /(node_modules)/,
                // 使用babel-loader
                use: {
                  loader: 'babel-loader',
                }
              }
            ]
        }
        // ...
    };
    

    执行命令验证编译结果

    yarn dev
    

    偷学VueCli和CRA脚手架,入门webpack配置工程师

    可以看到我们的const已经被转译成了var

    缺失的ES6+ API编译

    我们在index.js新增

    Promise.resolve(1)
    

    执行yarn dev

    偷学VueCli和CRA脚手架,入门webpack配置工程师

    可以看到我们的Promise并没有转译,也就会缺少API级别的兼容性

    配置ES6+ API编译

    babel将编译分成了2类,一类成为语法编译,一类称为polyfill

    语法:

    const a = 1
    // 编译
    var a  =  1
    

    polyfill

    Promise.resolve(1)
    // 通过引入Promise
    Promise = require('Promise')
    

    也就是我们需要找到一个实现了Promise同时符合ECMAScript的API实现包,目前推荐的是core-js,在babel的配置下是这样的

    babel.config.js

    module.exports = {
        presets: [
            [
                '@babel/preset-env',{
                    // 配置useBuiltIns为entry,防止依赖的第三方库没声明其es6+的API导致我们应用程序出错,不建议usage选项,需要在开发中熟悉第三方包是否使用到ES6+的API
                    useBuiltIns: 'entry',
                    // 使用corejs3版本,corejs2很早就冻结分支了,例如Array.prototype.flat只在corejs3版本
                    corejs: 3
                }
            ],
        ],
    };
    

    src/index.js

    // 引入core-js/stable和regenerator-runtime/runtime,相当于已经废弃的babel-polyfill
    import 'core-js/stable'
    import 'regenerator-runtime/runtime'
    
    const a = 1
    Promise.resolve(1)
    

    打包结果

    偷学VueCli和CRA脚手架,入门webpack配置工程师

    css引入支持

    src/css下新增globel.css,内容如下:

    body {
        background-color: rebeccapurple;
    }
    

    引入到src/index.js

    import './css/global.css'
    

    执行yarn dev

    偷学VueCli和CRA脚手架,入门webpack配置工程师 偷学VueCli和CRA脚手架,入门webpack配置工程师

    出现报错提示我们可能需要这个文件类型的loader,这里需要安装css-loader,同时配置webpack

    yarn add css-loader
    
    // 新增css文件处理
    module.exports = {
        module: {
            rules: [
                {
                    test: /\.css$/i,
                    use: ["css-loader"],
                },
            ]
        }
    };
    

    安装完毕后执行yarn dev,发现已经不报错了

    在src下新增index.html验证输出结果

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        
    </body>
    <script src="../dist/main.js"></script>
    </html>
    

    我们在浏览器打开index.html发现样式并没有生效,这个时候我们需要引入style-loader,用来实现转换css到浏览器

    yarn add style-loader
    

    webpack.config.js

    module.exports = {
        module: {
            rules: [
                {
                    test: /\.css$/i,
                    // 新增style-loader
                    use: ["style-loader","css-loader"],
                },
            ]
        }
    };
    

    执行yarn dev并刷新页面,看到css生效

    偷学VueCli和CRA脚手架,入门webpack配置工程师

    配置CSS私有前缀编译

    在一些特性没有完全实现的时候,浏览器厂商常常会使用前缀允许我们使用,这块可以通过postcss帮助我们在编译时完成

    安装依赖

    # postcss 用来编译css
    # postcss-loader postcss的webpack插件
    # postcss-preset-env类似@babel/preset-env,配置编译环境
    yarn add  postcss-loader postcss postcss-preset-env
    

    配置webpack

    module.exports = {
        module: {
            rules: [
                {
                    test: /\.css$/i,
                    // 新增postcss-loader
                    use: ["style-loader","css-loader", "postcss-loader"],
                },
            ]
        }
    };
    

    新增postcss配置文件

    postcss.config.js

    module.exports = {
        plugins: [
          [
            "postcss-preset-env",
            {
              // 其他选项
            },
          ],
        ],
    };
    

    新增项目兼容浏览器范围配置

    .browserslistrc

    last 2 versions
    

    修改global.css

    body {
        background-color: rebeccapurple;
        /* 新增flex属性 */
        display: flex;
    }
    

    执行编译验证结果

    偷学VueCli和CRA脚手架,入门webpack配置工程师

    编译后已经输出了flex的浏览器私有前缀

    配置css预编译语言

    这里我们配置sass

    安装依赖

    #  sass,sass的编译器,比node-sass兼容性好
    # sass-loader sass的webpack插件
    yarn add sass  sass-loader
    

    配置webpack

    module.exports = {
        module: {
            rules: [
                {
                    test: /\.s[ac]ss$/i,
                    use: [
                      "style-loader",
                      "css-loader",
                      "sass-loader",
                    ],
                  },
            ]
        }
    };
    

    修改文件后缀验证

    将src/css/global.css后缀改为scss,同时在index.js引入的后缀也改成css,运行yarn dev,打包成功

    配置svg

    目前svg比较合适的方法是通过svg sprite的方式来使用

    安装依赖

    # svgo svg优化
    # svgo-loader svgo webpack插件
    # svg-sprite-loader svg-sprite插件
    yarn add svgo-loader svgo svg-sprite-loader
    

    配置webpack

    webpack.config.js

    module.exports = {
    module: {
        rules: [
            {
                test: /\.svg$/,
                use: [
                    { loader: 'svg-sprite-loader', options: {
                        
                    } },
                    'svgo-loader'
                ]
            }
    
        ]
    },
    

    新增svg目录

    新增svg/index.js和svg/assets目录,在里面放入

    <svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><title>我的订单</title><path d="M20.23,4h0l16.12,6.37L19.93,16.22h-.11L3.7,9.86,20.15,4h.08m0-2a2.07,2.07,0,0,0-.78.14L.76,8.78a1.1,1.1,0,0,0,0,2.06l18.33,7.25a2.06,2.06,0,0,0,.77.14,2.11,2.11,0,0,0,.78-.14l18.69-6.63a1.11,1.11,0,0,0,0-2.07L21,2.15A2.06,2.06,0,0,0,20.23,2Z"/><path d="M19.79,27.9a3.14,3.14,0,0,1-1.13-.21l-18-7.13a1,1,0,0,1,.74-1.86l18,7.13a1.25,1.25,0,0,0,.83,0l18.51-6.57a1,1,0,1,1,.67,1.89L20.89,27.7A3.19,3.19,0,0,1,19.79,27.9Z"/><path d="M19.79,37.92a3.36,3.36,0,0,1-1.13-.2l-18-7.13a1,1,0,0,1-.56-1.3,1,1,0,0,1,1.3-.56l18,7.12a1.13,1.13,0,0,0,.83,0l18.51-6.56a1,1,0,1,1,.67,1.88l-18.5,6.56A3.19,3.19,0,0,1,19.79,37.92Z"/></svg>
    
    let req = require.context('./assets', false, /\.svg$/);
    
    let requireAll = function (requireContext) {
        requireContext.keys().map(requireContext);
    };
    
    requireAll(req);
    
    

    运行命令验证效果

    yarn dev

    偷学VueCli和CRA脚手架,入门webpack配置工程师

    支持静态资源

    安装依赖

    yarn add file-loader  url-loader
    

    配置webpack

    module.exports = {
        module: {
            rules: [
                {
                    test: /\.(png|jpg|gif)$/i,
                    use: [
                      {
                        loader: 'url-loader',
                        options: {
                          limit: 8192,
                        },
                      },
                    ],
                },
                {
                    test: /\.(png|jpe?g|gif)$/i,
                    use: [
                      {
                        loader: 'file-loader',
                      },
                    ],
                },
            ]
        },
    };
    

    配置Vue环境

    安装依赖

    # vue-loader vue-template-compiler vue 用来编译Vue文件
    # @vue/babel-preset-jsx @vue/babel-helper-vue-jsx-merge-props 支持Vue JSX写法
    yarn add vue-loader vue-template-compiler vue  @vue/babel-preset-jsx @vue/babel-helper-vue-jsx-merge-props
    

    配置webpack

    module.exports = {
        module: {
            rules: [
                {
                    test: /\.vue$/,
                    use: ['cache-loader', 'thread-loader','vue-loader'],
                },
    
            ]
        },
        plugins: [
            new VueLoaderPlugin()
        ],
    };
    

    新增文件验证

    新增src/test.vue,在index.js引入

    import testVue from './test.vue'
    console.log(testVue);
    

    执行yarn dev,看到控制台输出结果

    热更新

    自动注入依赖和复制html到dist目录

    安装依赖

    yarn add html-webpack-plugin
    

    配置webpack

    const HtmlWebpackPlugin = require('html-webpack-plugin');
    module.exports = {
        // 使用HtmlWebpackPlugin
        plugins: [new HtmlWebpackPlugin()]
    };
    

    配置热更新

    安装依赖

    # webpack-dev-server 热更新服务器
    # webpack-cli webpack命令包
    yarn add webpack-cli webpack-dev-server
    

    开启热更新

    const HtmlWebpackPlugin = require('html-webpack-plugin');
    module.exports = {
        // 开启热更新服务器配置
        devServer: {
            contentBase: './dist',
            hot: true,
        },
    };
    

    修改运行命令验证

    package.json

    "scripts": {
    "dev": "webpack serve"
    },
    

    运行yarn dev

    偷学VueCli和CRA脚手架,入门webpack配置工程师

    打开提示地址,查看结果,可以看到我们的代码已经在热更新服务器上运行,此时我们随意修改样式,可以实时生效

    分离生产和开发环境配置

    分离配置

    webpack.config.js

    const HtmlWebpackPlugin = require('html-webpack-plugin');
    module.exports = {
        entry: './src/index.js',
        module: {
            rules: [
                {
                    test: /\.js$/,
                    exclude: /(node_modules)/,
                    use: {
                        loader: 'babel-loader',
                    },
                },
            ]
        },
        plugins: [new HtmlWebpackPlugin()]
    };
    

    webpack.dev.config.js

    const baseWebpackConfig = require('./webpack.config')
    const { merge } = require('webpack-merge');
    module.exports =   merge(baseWebpackConfig, {
        mode:'development',
        devtool : 'eval-source-map',
        devServer: {
            contentBase: './dist',
            hot: true,
        },
        module: {
            rules: [
                {
                    test: /\.css$/i,
                    use: ["style-loader","css-loader", "postcss-loader"],
                },
                {
                    test: /\.s[ac]ss$/i,
                    use: [
                      "style-loader",
                      "css-loader",
                      "sass-loader",
                    ],
                },
            ]
        },
    });
    

    webpack.prod.config.js

    const baseWebpackConfig = require('./webpack.config')
    const { merge } = require('webpack-merge');
    module.exports =   merge(baseWebpackConfig, {
        mode:'production',
        devtool : 'source-map',
        module: {
            rules: [
                {
                    test: /\.css$/i,
                    use: ["style-loader","css-loader", "postcss-loader"],
                },
                {
                    test: /\.s[ac]ss$/i,
                    use: [
                      "style-loader",
                      "css-loader",
                      "sass-loader",
                    ],
                },
            ]
        },
    });
    

    添加开发命令和生产命令

    package.json

    "scripts": {
        "dev": "webpack serve --config=./webpack.dev.config.js",
        "build": "webpack --config=./webpack.prod.config.js"
    },
    

    运行命令尝试

    yarn dev

    配置压缩

    javascript压缩

    安装依赖

    # 安装4.0最新版本,5版本只支持webpack5
    terser-webpack-plugin@"^4.0.0"
    

    配置webpack

    webpack.prod.config.js

    const TerserPlugin = require("terser-webpack-plugin");
    module.exports =   merge(baseWebpackConfig, {
        optimization: {
            minimize: true,
            minimizer: [new TerserPlugin()],
        },
    });
    

    执行命令验证

    yarn build

    偷学VueCli和CRA脚手架,入门webpack配置工程师

    分离css到单独文件

    安装依赖

    yarn add mini-css-extract-plugin
    

    配置webpack

    webpack.prod.config.js

    const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    module.exports =   merge(baseWebpackConfig, {
        module: {
            rules: [
                {
                    test: /\.css$/i,
                    // 加上loader
                    use: [MiniCssExtractPlugin.loader,"css-loader", "postcss-loader"],
                },
                {
                    test: /\.s[ac]ss$/i,
                    // 加上loader
                    use: [
                      MiniCssExtractPlugin.loader,
                      "css-loader",
                      "sass-loader",
                    ],
                },
            ]
        },
        // 加上插件
        plugins: [new MiniCssExtractPlugin()],
    });
    

    执行命令验证

    执行yarn build,可以看到我们的dist文件下新增了一个main.css

    压缩css

    安装依赖

    yarn add css-minimizer-webpack-plugin
    

    配置webpack

    webpack.prod.config.js

    const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
    module.exports =   merge(baseWebpackConfig, {
        // 新增CssMinimizerPlugin压缩插件
        minimizer: [new TerserPlugin(),new CssMinimizerPlugin()],
    });
    

    运行命令验证

    yarn dev,看到main.css已经被压缩

    持久化缓存

    这里建议阅读这篇文章,详细讲述了每个情况下文件缓存名变化的应对方案,最终总结下来的配置如下:

    webpack.config.js

    module.exports = {
        output: { 
           filename: '[name].js',
           chunkFilename: '[name].js'
        }, 
    };
    

    webpack.prod.config.js

    module.exports =   merge(baseWebpackConfig, {
        plugins: 
        [   
            // 稳定css hash
            new MiniCssExtractPlugin(
                {
                    filename: '[name].[contenthash:8].css',
                    chunkFilename: '[name].[contenthash:8].css'
                }
            ),   
            // 稳定chunk ID
            new webpack.NamedChunksPlugin(
                chunk => chunk.name || Array.from(chunk.modulesIterable, m => m.id).join("_")
            ),
        ],
        // 稳定模块 ID
        optimization: {
            hashedModuleIds: true,
        },
        output: { 
            // 分离chunks 映射关系,避免chunk改动时主js hash变动
            runtimeChunk: true,
            // 稳定文件hash
            filename: '[name].[contenthash:8].js',
            // 稳定chunk hash
            chunkFilename: '[name].[contenthash:8].js'
        }, 
    });
    

    性能优化-速度

    并发

    javascript

    目前推荐使用官方的thread-loader,由于多线程有通信损耗,建议用在消耗大的loader,比如babel-loader

    yarn add thread-loader
    

    webpack.config.js

    module.exports = {
        module: {
            rules: [
                {
                    test: /\.js$/,
                    exclude: /(node_modules)/,
                    // 为babel添加thread-loader,多进程编译
                    use: ['thread-loader','babel-loader']
                },
            ]
        },
    };
    

    sass

    官方推荐使用使用fibers提升sass编译速度

    yarn add fibers
    
    {
        loader: "sass-loader",
        options: {
            sassOptions: {
                require("fibers"),
            },
        },
    },
    

    缓存

    目前推荐使用cache-loader

    yarn add  cache-loader
    

    webpack.config.js

    module.exports = {
        module: {
            rules: [
                {
                    test: /\.js$/,
                    exclude: /(node_modules)/,
                    // 添加cache-loader提高二次编译速度
                    use: ['cache-loader', 'thread-loader','babel-loader']
                },
            ]
        },
    };
    

    性能优化 - 体积

    分包

    webpack的默认分包只是分包异步块,我们需要自己调整一下

    webpack.config.js

    module.exports = {
        optimization: {
            splitChunks: {
                cacheGroups: {
                    // node_modules打包在一个文件,提高缓存率
                    vendors: {
                      name: `chunk-vendors`,
                      test: /[\\/]node_modules[\\/]/,
                      priority: -10,
                      chunks: 'initial'
                    },
                    // 提取引入超过2次的代码,减少打包体积
                    common: {
                      name: `chunk-common`,
                      minChunks: 2,
                      priority: -20,
                      chunks: 'initial',
                      reuseExistingChunk: true
                    }
                  }
            }
        }
    };
    

    执行yarn build可以看到dist下增加了一个chunk-vendors文件

    升级到webpack5

    升级webpack

    yarn add webpack
    

    升级terser-webpack-plugin

    yarn add terser-webpack-plugin
    

    移除持久化缓存选项

    webpack已经默认支持了moduleID和chunkID的稳定算法,所以这2个插件移除

    module.exports =   merge(baseWebpackConfig, {
        plugins: 
        [ 
            // new webpack.NamedChunksPlugin(
            //     chunk => chunk.name || Array.from(chunk.modulesIterable, m => m.id).join("_")
            // ),
        ],
        optimization: {
            //hashedModuleIds: true,
        },
     
    });
    

    删除cache-loader

    webpack5内置了缓存机制,缓存效果和缓存安全性更好,cache-loader可以删除

    更新html-webpack-plugin

    yarn add  html-webpack-plugin@next
    

    废弃file-loader和url-loader

    webpack 推出了资源这个概念,之前的file-loaderurl-loader已经被视为资源,如果资源配置满足你的话,迁移这个2个loader到对应的资源类型

    {
        test: /\.(png|jpg|gif)$/i,
        type: 'asset/resource'
    },
    // {
    //     test: /\.(png|jpg|gif)$/i,
    //     use: [
    //       {
    //         loader: 'url-loader',
    //         options: {
    //           limit: 8192,
    //         },
    //       },
    //     ],
    // },
    {
        test: /\.(png|jpg|gif)$/i,
        type: 'asset/inline'
    },
    
    // {
    //     test: /\.(png|jpe?g|gif)$/i,
    //     use: [
    //       {
    //         loader: 'file-loader',
    //       },
    //     ],
    // },
    

    热更新失效

    需要把target设置为web平台

    webpack.config.js

    module.exports = {
        target: 'web'
    }
    

    热更新overlay失效

    配置失效

    在尝试触发一个错误并且配置了devServeroverlay属性,发现错误弹窗没有显示错误信息

    devServer: {
        static: {
            directory: './dist',
        },
        // 配置了错误弹窗
        overlay: {
            warnings: true,
            errors: true
        }
    },
    

    偷学VueCli和CRA脚手架,入门webpack配置工程师

    webpack-dev-server未适配

    经过调试和阅读源码发现问题是webpack-dev-server3.0还没适配webpack5

    升级适配的webpack-dev-server版本

    可以升级到正常适配webpack5beta版,执行

    yarn add webpack-dev-server@next 
    

    调试打补丁

    安装完还是发现显示不了,继续调试,发现是这里的变量没有赋值,由于先用patch-package自己先打个补丁

    安装依赖

    yarn add patch-package
    

    修改文件

    node_modules\webpack-dev-server\lib\utils\normalizeOptions.js

      options.clientOverlay =
        typeof options.overlay !== 'undefined' ? options.overlay : false;
    
    

    偷学VueCli和CRA脚手架,入门webpack配置工程师

    执行patch

    npx patch-package webpack-dev-server
    

    重新运行查看结果

    偷学VueCli和CRA脚手架,入门webpack配置工程师

    给webpack-dev-server提PR

    PR步骤:

    • fork开源仓库

    • 修改代码,通过仓库的规范检查(风格、质量、类型检查),同时要新增单元测试并通过当时的所有测试,在webpack-dev-server表现为

    偷学VueCli和CRA脚手架,入门webpack配置工程师

    • 推送到自己的远程仓库

    • 在原仓库发起PR

    • 给维护者用三级英语交流

    PR地址


    起源地下载网 » 偷学VueCli和CRA脚手架,入门webpack配置工程师

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元