【问题标题】:how to make webpack import polyfills only for a specific build?如何仅为特定构建制作 webpack 导入 polyfill?
【发布时间】:2020-11-01 08:44:26
【问题描述】:

我刚刚设法让 webpack 创建了两个单独的构建,一个用于 es5,另一个用于 es6。 请参阅下面的配置文件:

const path = require("path");

const common = require("./webpack.common");
const merge = require("webpack-merge");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const TerserPlugin = require("terser-webpack-plugin");
var HtmlWebpackPlugin = require("html-webpack-plugin");

const es5Config = merge(common,{
  mode: "production",
  output: {
    filename: "[name].[contentHash].bundle.es5.js",
    path: path.resolve(__dirname, "dist")
  },
  optimization: {
    minimizer: [
      new OptimizeCssAssetsPlugin(),
      new TerserPlugin(),
      new HtmlWebpackPlugin({
        template: "./src/template.html",
        minify: {
          removeAttributeQuotes: true,
          collapseWhitespace: true,
          removeComments: true
        }
      }),
    ]
  },
  plugins: [

    new MiniCssExtractPlugin({ filename: "[name].[contentHash].css" }),
      new CleanWebpackPlugin(),
    ],

  module: {
    rules: [
      {
        test: /\.scss$/,
        use: [
          MiniCssExtractPlugin.loader, //3. Extract css into files
          "css-loader", //2. Turns css into commonjs
          "sass-loader" //1. Turns sass into css
        ]
      },
      {
      test: /\.m?js$/,
      exclude: /node_modules/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: [
            ['@babel/preset-env', {
              modules: false,
              useBuiltIns: 'entry',
              targets: {
                browsers: [
                  "IE 11"
                ],
              },
            }],
          ],
        },
      },
    }],
  },
});

const es6Config = merge(common, {
  mode: "production",
  output: {
    filename: "[name].[contentHash].bundle.es6.js",
    path: path.resolve(__dirname, "dist")
  },
  optimization: {
    minimizer: [
      new OptimizeCssAssetsPlugin(),
      new TerserPlugin(),
      new HtmlWebpackPlugin({
        template: "./src/template.html",
        minify: {
          removeAttributeQuotes: true,
          collapseWhitespace: true,
          removeComments: true
        }
      }),
    ]
  },
  plugins: [

    new MiniCssExtractPlugin({ filename: "[name].[contentHash].css" }),
      new CleanWebpackPlugin(),
    ],
  module: {
    rules: [
      {
        test: /\.scss$/,
        use: [
          MiniCssExtractPlugin.loader, //3. Extract css into files
          "css-loader", //2. Turns css into commonjs
          "sass-loader" //1. Turns sass into css
        ]
      },
      {
      test: /\.m?js$/,
      exclude: /node_modules/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: [
            ['@babel/preset-env', {
              modules: false,
              useBuiltIns: "usage",
              targets: {
                browsers: [
                  'Chrome >= 60',
                  'Safari >= 10.1',
                  'iOS >= 10.3',
                  'Firefox >= 54',
                  'Edge >= 15',
                ],
              },
            }],
          ],
        },
      },
    }],
  },
});

module.exports = [es5Config, es6Config];

现在的问题是我希望 webpack 只为 es5 构建导入 polyfill。并使用设置为使用的 usebuilins 无法填充任何内容。

我可能用错了可能与 node_modules 包有关的东西吗??

所以我只是在主文件中导入 polyfill,例如:

import "core-js/stable";
import "regenerator-runtime/runtime";

我怎样才能使这些导入只为 es5 构建添加?或者如何包含来自 webpack 的 polyfills/imports?

如果有人知道,还有一个额外的问题,我怎样才能正确使用带有“用法”的 usebuiltins?因为到目前为止,即使我以为我的主文件添加了 polifylls,例如,我仍然在 IE11 中遇到 Symbols 错误。

【问题讨论】:

    标签: javascript webpack polyfills babel-polyfill


    【解决方案1】:

    我想通了。这是 webpack 配置: 常见的:

    const path = require("path");
    
    module.exports = {
      entry: {
        main: "./src/index.js",
        vendor: "./src/vendor.js"
      },
      module: {
        rules: [
          {
            test: /\.html$/,
            use: ["html-loader"]
          },
          {
            test: /\.(svg|png|jpg|gif)$/,
            use: {
              loader: "file-loader",
              options: {
                name: "[name].[hash].[ext]",
                outputPath: "imgs"
              }
            }
          }
        ]
      }
    };
    

    产品:

    const path = require("path");
    
    const common = require("./webpack.common");
    const merge = require("webpack-merge");
    const CleanWebpackPlugin = require("clean-webpack-plugin");
    const MiniCssExtractPlugin = require("mini-css-extract-plugin");
    const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin");
    const TerserPlugin = require("terser-webpack-plugin");
    var HtmlWebpackPlugin = require("html-webpack-plugin");
    const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
    
    const es5Config = merge(common,{
      mode: "production",
      output: {
        filename: "[name].[contentHash].bundle.es5.js",
        path: path.resolve(__dirname, "dist")
      },
      optimization: {
        runtimeChunk: 'single',
        splitChunks: {
          chunks: 'all',
          maxInitialRequests: Infinity,
          minSize: 0,
          cacheGroups: {
            vendor: {
              test: /[\\/]node_modules[\\/]/,
              name: (module) => {
                // get the name. E.g. node_modules/packageName/not/this/part.js
                // or node_modules/packageName
                const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
                // npm package names are URL-safe, but some servers don't like @ symbols
                return `npm.${packageName.replace('@', '')}`;
              },
            },
          },
        },
        minimizer: [
          new OptimizeCssAssetsPlugin(),
          new TerserPlugin(),
          new HtmlWebpackPlugin({
            filename: 'main.aspx',
            template: "./src/main.html",
            // minify: {
            //   removeAttributeQuotes: true,
            //   collapseWhitespace: true,
            //   removeComments: true
            // }
          }),
        ]
      },
      plugins: [
        new MiniCssExtractPlugin({ filename: "[name].[contentHash].css" }),
        new CleanWebpackPlugin(),
        new BundleAnalyzerPlugin(),
        ],
    
      module: {
        rules: [
          {
            test: /\.scss$/,
            use: [
              MiniCssExtractPlugin.loader, //3. Extract css into files
              "css-loader", //2. Turns css into commonjs
              "sass-loader" //1. Turns sass into css
            ]
          },
          {
          test: /\.m?js$/,
          exclude: /node_modules/,
          //exclude: /node_modules\/(?!(\@pnp)\/).*/, 
          use: {
            loader: 'babel-loader',
            options: {
              //configFile : './es5.babel.config.json',
              presets: [
                ['@babel/preset-env', {
                  modules: false,
                  useBuiltIns: false,
                  targets: {
                    browsers: [
                      "IE 11"
                    ],
                  },
                }],
              ],
            },
          },
        }],
      },
    });
    
    const es6Config = merge(common, {
      mode: "production",
      output: {
        filename: "[name].[contentHash].bundle.es6.js",
        path: path.resolve(__dirname, "dist")
      },
      optimization: {
        runtimeChunk: 'single',
        splitChunks: {
          chunks: 'all',
          maxInitialRequests: Infinity,
          minSize: 0,
          cacheGroups: {
            vendor: {
              test: /[\\/]node_modules[\\/]/,
              name: (module) => {
                // get the name. E.g. node_modules/packageName/not/this/part.js
                // or node_modules/packageName
                const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
                // npm package names are URL-safe, but some servers don't like @ symbols
                return `npm.${packageName.replace('@', '')}`;
              },
            },
          },
        },
        minimizer: [
          new OptimizeCssAssetsPlugin(),
          new TerserPlugin(),
          new HtmlWebpackPlugin({
            filename: 'main_es6.html',
            template: "./src/main.html",
            // minify: {
            //   removeAttributeQuotes: true,
            //   collapseWhitespace: true,
            //   removeComments: true
            // }
          }),
        ]
      },
      plugins: [
    
        new MiniCssExtractPlugin({ filename: "[name].[contentHash].css" }),
        new CleanWebpackPlugin(),
        ],
      module: {
        rules: [
          {
            test: /\.scss$/,
            use: [
              MiniCssExtractPlugin.loader, //3. Extract css into files
              "css-loader", //2. Turns css into commonjs
              "sass-loader" //1. Turns sass into css
            ]
          },
      ],
      },
    });
    module.exports = [ es5Config, es6Config];
    

    babel.config.json:

    {
      "plugins": [
        [
          "@babel/plugin-transform-runtime",
          {
            "absoluteRuntime": true,
            "helpers": true,
            "regenerator": true,
            "useESModules": false
          }
        ]
      ]
    }
    

    因此,这与 cdn polyfill 相结合可以仅为 IE11 加载 polifylls。它也有自己的构建。

    这里唯一的问题是生成的输出将具有分离的文件,并且 es5 构建的所有脚本中都应该没有模块。同样对于 es6 都应该有模块。 然后我必须去手动添加那些我可以轻松制作自定义模板来处理的内容。

    但是,polyfill 的脚本被删除了,我仍然需要手动合并 html 文件。有谁知道怎么处理?

    编辑: 1 - 对于属性,您可以使用 HtmlWebpackPlugin hooks () 或 ScriptExtHtmlWebpackPlugin 将属性放置在标签中。

    在这里找到一些带有钩子的代码:

    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    
    class es5TagTransformerHook {
      apply (compiler) {
        compiler.hooks.compilation.tap('MyPlugin', (compilation) => {
      
          HtmlWebpackPlugin.getHooks(compilation).alterAssetTagGroups.tapAsync(
            'es5TagTransformerHook', stacktraces
            async (data, cb) => {
              // Manipulate the content
              // data.html += 'The Magic Footer'
              // Tell webpack to move on
              data.bodyTags.forEach(t=>t.tagName === 'script'?t.attributes.nomodule = true:null)
    
              cb(null, data)
            }
          )
          
        })
      }
    }
    
    module.exports = es5TagTransformerHook
    

    2 - 为了合并生成的 html,我最终使用了这个要点: https://gist.github.com/agoldis/21782f3b9395f78d28dce23e3b6ddd56

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-13
      • 1970-01-01
      • 2017-07-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多