【问题标题】:How can I replace files at compile time using webpack?如何在编译时使用 webpack 替换文件?
【发布时间】:2018-12-22 15:05:35
【问题描述】:

我有一个具有多种配置的项目。第一个配置是config.dev.js 文件,其中包含一些开发配置。我在开发模式下使用它。第二个配置是config.js 文件。我在生产模式下使用它。

在我使用导入的代码中:

import * as config from './config.js';

我想在开发中使用第一个配置文件,在生产中使用第二个配置文件而不重写所有导入。如何根据构建模式替换此配置?

【问题讨论】:

    标签: javascript webpack webpack-4 webpack-loader


    【解决方案1】:

    另一种方法是使用 Webpack.DefinePlugin。如果您想要有条件地包含一个很小的代码块,则特别有用。

    示例如下:

    // webpack.conf.js
    // Code block that should be inserted or left blank
    const ServiceWorkerReg = `window.addEventListener('load', () => {
        navigator.serviceWorker.register('service-worker.js').then(registration => {
            console.log('SW registered: ', registration);
        }).catch(registrationError => {
            console.log('SW registration failed: ', registrationError);
        });
    });`
    
    
    appConfig = {
        plugins: [
            new webpack.DefinePlugin({
                __SERVICE_WORKER_REG: isDev ? '' : ServiceWorkerReg,
            }),
        ]
        ...
    }
    
    
    
     // Some module index.js
    
     __SERVICE_WORKER_REG
    
     ... // other non conditional code
    

    【讨论】:

      【解决方案2】:

      这是一个老问题,但我最近偶然发现了同样的问题,webpack.NormalModuleReplacementPlugin 似乎不再起作用(或者至少在我使用 JSON 文件作为配置的情况下不起作用)。相反,我找到了另一个使用别名的解决方案:

      const path = require("path");
      
      modules.export = {
          ...
          resolve: {
              ...
              alias: {
                  [path.resolve(__dirname, "src/conf/config.json")]:
                      path.resolve(__dirname, "src/conf/config.prod.json")
              }
          }
          ...
      }
      

      【讨论】:

      • NormalModuleReplacementPlugin 在我的使用过程中也不起作用,同时它错误“NormalModuleFactory.beforeResolve 不再是瀑布挂钩,而是一个吊钩。”似乎与 webpack 版本变化有关:github.com/webpack/webpack/issues/11647
      【解决方案3】:

      我想模仿 Angular 的 fileReplacements 语法,所以我使用了类似 Angular 的 config.json,如果配置键与我传递给 webpack 的 env 匹配,则循环替换并创建几个 Webpack 模块规则。

      这不是有史以来最优雅的东西,但这是我最终得到的:

      // config.json
      
      {
          "title": "Some Title",
          "configurations": {
              "production": {
                  "fileReplacements": [
                      {
                          "replace": "src/environments/environment.ts",
                          "with": "src/environments/environment.prod.ts"
                      }
                  ]
              },
              "lan": {
                  "fileReplacements": [
                      {
                          "replace": "src/environments/environment.ts",
                          "with": "src/environments/environment.lan.ts"
                      }
                  ]
              }
          }
      }
      
      
      // webpack.config.js
      
      const appConfig = require('./config.json');
      
      
      
      module.exports = (env, argv) => {
      
          // env.build is like `ng build --prod` as `webpack --env.build=production` 
          const configuration = appConfig.configurations[env.build];
          const fileReplacements = [];
      
          // Safety Check
          if(configuration && configuration.fileReplacements) {
      
              // Iterate through replacements
              for(const replacement of configuration.fileReplacements) {
                  // create Webpack module rule
                  const replace = {
                      test: path.resolve(replacement.replace),
                      loader: 'file-replace-loader',
                      options: {
                          replacement: path.resolve(replacement.with),
                          async: true
                      }
                  }
                  fileReplacements.push(replace);
              }
          }
      
          return {
              mode: //...
              entry: //...
              module: {
                  rules: [
                      {
                          //...
                      },
                      // Unpack anywhere here
                      ...fileReplacements
                  ]
             }
          }
      }
      
      

      这样你就不必一直搞乱 webpack 和 regex 测试,只需添加到 config.json 中的数组中

      【讨论】:

      • 这基本上也是我想做的。喜欢你的解决方案。不敢相信每个框架都不包含这样的东西。如果没有它,你会想要构建一个应用程序——或者在本地调试一个生产错误吗?
      【解决方案4】:

      你也可以像这样使用babel-loader

      //webpack.config.js
      
      const resolve = require('path').resolve;
      
      module.exports = {
        //...
        module: {
          strictExportPresence: true,
          rules: [{
            test: /\.config\.js$/,
            include: paths.appSrc,
            loader: require.resolve('babel-loader'),
            options: {
              plugins: [
                  [
                    "module-resolver",
                    {
                      resolvePath(sourcePath, currentFile, opts) {
                        if(process.env.NODE_ENV === 'development') {
                          return sourcePath.substr(0, sourcePath.lastIndexOf('/')) + '/config.dev.js';
                        } else {
                          return sourcePath;
                        }
                      }
                    }
                  ]
                ]
              }
          }]
        }
      }
      

      这样您甚至可以定义复杂的算法来确定您要使用的文件。

      【讨论】:

        【解决方案5】:

        我知道这是一篇旧帖子,但这是 Google 上的首批结果之一,所以我认为更好的答案会更好。

        Webpack 有一个内置的“Normal Module Replacement Plugin”。

        plugins: [
          new webpack.NormalModuleReplacementPlugin(
            /some\/path\/config\.development\.js/,
            './config.production.js'
          )
        ]
        

        为了我的使用,我把 env 文件放在了一个变量下面是一个例子:

        let envFilePath = './environment.dev.js';
        if (env === 'production') {
          envFilePath = './environment.prod.js';
        } else if (env === 'staging') {
          envFilePath = './environment.stg.js';
        }
        
        module.exports = {
            // other webpack stuff
            ....
            plugins:[ 
                new webpack.NormalModuleReplacementPlugin(
                    /src\/environment\/environment\.js/,
                    envFilePath
                ),
                ...
            ]
        }
        

        【讨论】:

        • 也许值得一提的是,第二条路径是相对于第一条的,意思是:如果我的旧路径在./src/config/dev.js 中,那么./prod.js 将引用./src/config/prod.js,而不是root/prod.js
        【解决方案6】:

        你可以使用 webpack 文件替换加载器

        https://www.npmjs.com/package/file-replace-loader

        例子:

        //webpack.config.js
        
        const resolve = require('path').resolve;
        
        module.exports = {
          //...
          module: {
            rules: [{
              test: /\.config\.js$/,
              loader: 'file-replace-loader',
              options: {
                condition: process.env.NODE_ENV === 'development',
                replacement: resolve('./config.dev.js'),
                async: true,
              }
            }]
          }
        }
        

        【讨论】:

          猜你喜欢
          • 2018-08-26
          • 1970-01-01
          • 2018-12-27
          • 2019-05-17
          • 2019-12-11
          • 1970-01-01
          • 2019-02-01
          • 2011-10-24
          • 2020-10-25
          相关资源
          最近更新 更多