Javascript 基于Webpack环境的条件构建

Javascript 基于Webpack环境的条件构建,javascript,build,conditional,require,webpack,Javascript,Build,Conditional,Require,Webpack,我有一些需要开发的东西,例如mock,我不想让它膨胀我的分布式构建文件 在RequireJS中,您可以在插件文件中传递一个配置文件,并根据该文件有条件地要求输入内容 对于webpack,似乎没有一种方法可以做到这一点。首先,要为环境创建运行时配置,我已使用该配置根据环境重新指向require,例如: // All settings. var all = { fish: 'salmon' }; // `envsettings` is an alias resolved at build

我有一些需要开发的东西,例如mock,我不想让它膨胀我的分布式构建文件

在RequireJS中,您可以在插件文件中传递一个配置文件,并根据该文件有条件地要求输入内容

对于webpack,似乎没有一种方法可以做到这一点。首先,要为环境创建运行时配置,我已使用该配置根据环境重新指向require,例如:

// All settings.
var all = {
    fish: 'salmon'
};

// `envsettings` is an alias resolved at build time.
module.exports = Object.assign(all, require('envsettings'));
然后,在创建webpack配置时,我可以动态分配
envsettings
指向的文件(即
webpackConfig.resolve.alias.envsettings='./'+env

然而,我想做一些类似的事情:

if (settings.mock) {
    // Short-circuit ajax calls.
    // Require in all the mock modules.
}
但是很明显,如果环境不是mock,我不想在这些mock文件中构建

我可以再次使用resolve.alias手动将所有这些要求重新指向存根文件,但有没有一种方法让我感觉不那么黑客

你知道我该怎么做吗?谢谢。

您可以使用

我在网页包构建文件中使用它,其中
env
是导出设置对象的文件路径:

// Webpack build config
plugins: [
    new webpack.DefinePlugin({
        ENV: require(path.join(__dirname, './path-to-env-files/', env))
    })
]

// Settings file located at `path-to-env-files/dev.js`
module.exports = { debug: true };
然后在你的代码中

if (ENV.debug) {
    console.log('Yo!');
}

如果条件为false,它将从构建文件中删除此代码。您可以看到一个工作模式。

另一种方法是使用JS文件作为代理,并让该文件在
commonjs
中加载感兴趣的模块,并将其导出为
es2015模块,如下所示:

// file: myModule.dev.js
module.exports = "this is in dev"

// file: myModule.prod.js
module.exports = "this is in prod"

// file: myModule.js
let loadedModule
if(WEBPACK_IS_DEVELOPMENT){
    loadedModule = require('./myModule.dev.js')
}else{
    loadedModule = require('./myModule.prod.js')
}

export const myString = loadedModule
然后您可以在应用程序中正常使用ES2015模块:

// myApp.js
import { myString } from './store/myModule.js'
myString // <- "this is in dev"
//myApp.js
从“./store/myModule.js”导入{myString}

myString/我最终使用了类似的东西,但担心两点:

  • 每次使用
    ENV
    (这对大型配置不好)时,都会注入完整的配置
  • 我必须定义多个入口点,因为
    require(env)
    指向不同的文件

  • 我想到的是一个简单的编写器,它构建一个配置对象并将其注入到配置模块中。
    以下是Iam为此使用的文件结构:

    config/
     └── main.js
     └── dev.js
     └── production.js
    src/
     └── app.js
     └── config.js
     └── ...
    webpack.config.js
    
    main.js
    保存所有默认配置文件:

    // main.js
    const mainConfig = {
      apiEndPoint: 'https://api.example.com',
      ...
    }
    
    module.exports = mainConfig;
    
    dev.js
    production.js
    仅包含覆盖主配置的配置内容:

    // dev.js
    const devConfig = {
      apiEndPoint: 'http://localhost:4000'
    }
    
    module.exports = devConfig;
    
    重要的部分是组成配置的
    webpack.config.js
    ,它使用生成一个环境变量
    \uuuu APP\u config\uuuu
    ,该变量保存组合的配置对象:

    const argv = require('yargs').argv;
    const _ = require('lodash');
    const webpack = require('webpack');
    
    // Import all app configs
    const appConfig = require('./config/main');
    const appConfigDev = require('./config/dev');
    const appConfigProduction = require('./config/production');
    
    const ENV = argv.env || 'dev';
    
    function composeConfig(env) {
      if (env === 'dev') {
        return _.merge({}, appConfig, appConfigDev);
      }
    
      if (env === 'production') {
        return _.merge({}, appConfig, appConfigProduction);
      }
    }
    
    // Webpack config object
    module.exports = {
      entry: './src/app.js',
      ...
      plugins: [
        new webpack.DefinePlugin({
          __APP_CONFIG__: JSON.stringify(composeConfig(ENV))
        })
      ]
    };
    
    最后一步是
    config.js
    ,它看起来是这样的(这里使用es6导入导出语法,因为它位于网页包下):

    在你的
    app.js
    中,你现在可以使用
    importconfig from./config'
    获取配置对象。

    使用。在源文件中,您可以执行以下操作

    /// #if ENV === 'production'
    console.log('production!');
    /// #endif
    
    相关的
    网页
    配置为

    const preprocessor = {
      ENV: process.env.NODE_ENV || 'development',
    };
    
    const ifdef_query = require('querystring').encode({ json: JSON.stringify(preprocessor) });
    
    const config = {
      // ...
      module: {
        rules: [
          // ...
          {
            test: /\.js$/,
            exclude: /node_modules/,
            use: {
              loader: `ifdef-loader?${ifdef_query}`,
            },
          },
        ],
      },
      // ...
    };
    
    不确定为什么“webpack.DefinePlugin”答案是定义基于环境的导入/需求的首选答案

    这种方法的问题是,您仍然在向客户机交付所有这些模块,例如->检查。并且根本不减少bundle.js的大小:)

    因此,真正有效且更符合逻辑的是:

    因此,与其执行on_client conditional require->首先不要将不需要的文件包含到包中


    希望这会有所帮助虽然这不是最好的解决方案,但它可能会满足您的一些需求。如果要在节点和浏览器中运行不同的代码,请使用此选项:

    if (typeof window !== 'undefined') 
        return
    }
    //run node only code now
    

    使用环境变量创建开发和产品部署:


    我一直在努力在我的网页配置中设置env。我通常希望设置env,以便在
    webpack.config.js
    postsss.config.js
    和入口点应用程序本身(
    index.js
    通常)中可以访问它。我希望我的发现能帮助别人

    我提出的解决方案是传入
    --env production
    --env development
    ,然后在
    webpack.config.js
    中设置模式。 但是,这并不能帮助我在需要的地方访问
    env
    (见上文),因此我还需要按照建议显式设置
    process.env.NODE\u env
    。 下面是我在
    webpack.config.js
    中看到的最相关的部分

    。。。
    module.exports=模式=>{
    process.env.NODE_env=模式;
    如果(模式=“生产”){
    返回merge(commonConfig,productionConfig,{mode});
    }
    返回合并(commonConfig,developmentConfig,{mode});
    };
    
    面临着与OP相同的问题,并且由于许可,在某些版本中不包含某些代码,我采用了如下方法:

    在build命令中,我为构建设置了一个适当的环境变量。例如package.json中的“demo”:

    ...
      "scripts": {
        ...
        "buildDemo": "./node_modules/.bin/webpack --config webpack.config/demo.js --env.demo --progress --colors",
    ...
    
    我阅读的文档中缺少的令人困惑的一点是,我必须通过确保我的env变量被注入到全局流程中,从而在我的webpack.config/demo.js中使其在整个构建过程中可见

    /* The demo includes project/reports action to access placeholder graphs.
    This is achieved by using the webpack-conditional-loader process.env.demo === true
     */
    
    const config = require('./production.js');
    config.optimization = {...(config.optimization || {}), minimize: false};
    
    module.exports = env => {
      process.env = {...(process.env || {}), ...env};
      return config};
    
    有了这一点,我可以有条件地排除任何内容,确保所有相关代码都能正确地从生成的JavaScript中删除。例如,在my routes.js中,演示内容被排除在其他版本之外,因此:

    ...
    // #if process.env.demo
    import Reports from 'components/model/project/reports';
    // #endif
    ...
    const routeMap = [
      ...
      // #if process.env.demo
      {path: "/project/reports/:id", component: Reports},
      // #endif
    ...
    

    这适用于webpack 4.29.6。

    请注意,目前我已使用alias在我不想要的环境中指向一个空(存根)文件(例如,require('mocks'))将指向非模拟环境上的一个空文件。似乎有点黑客,但它可以工作。if/else和require的唯一问题是,两个必需的文件都将绑定到生成的文件中。我还没有找到解决方法。基本上,绑定首先发生,然后损坏。如果您在网页包文件中使用插件
    w,则不一定如此ebpack.optimize.UglifyJsPlugin()
    ,网页的优化不会加载模块,a
    ...
    // #if process.env.demo
    import Reports from 'components/model/project/reports';
    // #endif
    ...
    const routeMap = [
      ...
      // #if process.env.demo
      {path: "/project/reports/:id", component: Reports},
      // #endif
    ...