在webpack中传递依赖于环境的变量

时间:2015-05-04 12:20:14

标签: javascript webpack

我正在尝试将一个角度应用程序从gulp转换为webpack。在gulp我使用gulp-preprocess来替换html页面中的一些变量(例如数据库名称),具体取决于NODE_ENV。使用webpack实现类似结果的最佳方法是什么?

18 个答案:

答案 0 :(得分:397)

实现这一目标有两种基本方法。

DefinePlugin

new webpack.DefinePlugin({
    'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
}),

请注意,这只会替换匹配"原样"。这就是字符串格式的原因。你可能有一个更复杂的结构,比如那里的一个物体,但你明白了。

EnvironmentPlugin

new webpack.EnvironmentPlugin(['NODE_ENV'])

EnvironmentPlugin在内部使用DefinePlugin并将环境值映射到代码。更简洁的语法。

别名

或者,您可以通过an aliased module使用配置。从消费者的角度来看,它看起来像这样:

var config = require('config');

配置本身可能如下所示:

resolve: {
    alias: {
        config: path.join(__dirname, 'config', process.env.NODE_ENV)
    }
}

我们说process.env.NODE_ENVdevelopment。它会映射到./config/development.js然后。它映射到的模块可以导出如下配置:

module.exports = {
    testing: 'something',
    ...
};

答案 1 :(得分:104)

另一种选择,如果您只想使用cli接口,只需使用webpack的define选项即可。我在package.json中添加了以下脚本:

"build-production": "webpack -p --define process.env.NODE_ENV='\"production\"' --progress --colors"

所以我必须运行npm run build-production

答案 2 :(得分:64)

我调查了几个关于如何设置特定于环境的变量的选项,并最终得到了这个:

我目前有2个webpack配置:

<强> webpack.production.config.js

new webpack.DefinePlugin({
  'process.env':{
    'NODE_ENV': JSON.stringify('production'),
    'API_URL': JSON.stringify('http://localhost:8080/bands')
  }
}),

<强> webpack.config.js

new webpack.DefinePlugin({
  'process.env':{
    'NODE_ENV': JSON.stringify('development'),
    'API_URL': JSON.stringify('http://10.10.10.10:8080/bands')
  }
}),

在我的代码中,我以这种(简短的)方式获得API_URL的值:

const apiUrl = process.env.API_URL;

编辑2016年11月3日

Webpack文档有一个例子:https://webpack.js.org/plugins/define-plugin/#usage

new webpack.DefinePlugin({
    PRODUCTION: JSON.stringify(true),
    VERSION: JSON.stringify("5fa3b9"),
    BROWSER_SUPPORTS_HTML5: true,
    TWO: "1+1",
    "typeof window": JSON.stringify("object")
})

使用 ESLint ,如果您有no-undef规则,则需要在代码中明确允许未定义的变量。 http://eslint.org/docs/rules/no-undef喜欢这样:

/*global TWO*/
console.log('Running App version ' + TWO);

编辑2017年9月7日(特定于Create-React-App)

如果您没有配置太多,请查看Create-React-App:Create-React-App - Adding Custom Environment Variables。在引擎盖下,CRA无论如何都使用Webpack。

答案 3 :(得分:22)

您可以直接使用Dim ws As Worksheet Set ws = Sheets("SheetName1") Dim rng As Range, cell As Range Set rng = ws.Range("C5","AJ5") Dim i as Integer i = 5 'this is an arbitrary number, change to whatever number of worksheets 'you wish to exclude that are at the beginning (left most side) of your workbook 'also assumes "SheetName1" is before this number. For Each cell In rng Sheets(i).Name = cell.Value i = i + 1 Next cell 中提供的EnvironmentPlugin来访问转换过程中的任何环境变量。

您只需在webpack文件中声明插件:

webpack.config.js

请注意,您必须明确声明要使用的环境变量的名称。

答案 4 :(得分:22)

您可以使用--env传递任何命令行参数而无需其他插件,因为webpack 2:

webpack --config webpack.config.js --env.foo=bar

使用webpack.config.js中的变量:

module.exports = function(env) {
    if (env.foo === 'bar') {
        // do something
    }
}

Source

答案 5 :(得分:13)

由于above post by thevangelist上的修改未获批准,请发布其他信息。

如果您想从 package.json 中选择值,例如已定义的 版本号 ,请通过 DefinePlugin 在Javascript内部。

{"version": "0.0.1"}

然后,在 webpack.config 中导入 package.json ,使用导入变量访问该属性,然后使用 DefinePlugin

const PACKAGE = require('../package.json');
const _version = PACKAGE.version;//Picks the version number from package.json

例如 webpack.config 上的某些配置正在使用METADATA进行DefinePlugin:

const METADATA = webpackMerge(commonConfig({env: ENV}).metadata, {
  host: HOST,
  port: PORT,
  ENV: ENV,
  HMR: HMR,
  RELEASE_VERSION:_version//Version attribute retrieved from package.json
});

new DefinePlugin({
        'ENV': JSON.stringify(METADATA.ENV),
        'HMR': METADATA.HMR,
        'process.env': {
          'ENV': JSON.stringify(METADATA.ENV),
          'NODE_ENV': JSON.stringify(METADATA.ENV),
          'HMR': METADATA.HMR,
          'VERSION': JSON.stringify(METADATA.RELEASE_VERSION)//Setting it for the Scripts usage.
        }
      }),

在任何打字稿文件中访问此内容:

this.versionNumber = process.env.VERSION;

最明智的方式是:

// webpack.config.js
plugins: [
    new webpack.DefinePlugin({
      VERSION: JSON.stringify(require("./package.json").version)
    })
  ]

Thanks to Ross Allen

答案 6 :(得分:12)

要个人添加一堆答案,我更喜欢以下内容:

const webpack = require('webpack');
const prod = process.argv.indexOf('-p') !== -1;

module.exports = {
  ...
  plugins: [
    new webpack.DefinePlugin({
      process: {
        env: {
          NODE_ENV: prod? `"production"`: '"development"'
        }
      }
    }),
    ...
  ]
};

使用它没有任何时髦的env变量或跨平台问题(使用env vars)。您所做的就是分别为dev或production运行正常的webpackwebpack -p

参考:Github issue

答案 7 :(得分:11)

另一个答案类似于@ zer0chain的回答。但是,有一个区别。

设置webpack -p就足够了。

与以下内容相同:

--define process.env.NODE_ENV="production"

这与

相同
// webpack.config.js
const webpack = require('webpack');

module.exports = {
  //...

  plugins:[
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('production')
    })
  ]
};

因此,在package.json节点文件中可能只需要这样的内容:

{
  "name": "projectname",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "debug": "webpack -d",
    "production": "webpack -p"
  },
  "author": "prosti",
  "license": "ISC",
  "dependencies": {    
    "webpack": "^2.2.1",
    ...
  }
}

来自DefinePlugin的一些提示:

  

DefinePlugin允许您创建可在编译时配置的全局常量。这对于允许开发构建和发布构建之间的不同行为非常有用。例如,您可以使用全局常量来确定是否进行日志记录;也许您在开发构建中执行日志记录,但在发布版本中不执行。这就是DefinePlugin促成的那种场景。

这样就可以检查您是否输入了webpack --help

Config options:
  --config  Path to the config file
                         [string] [default: webpack.config.js or webpackfile.js]
  --env     Enviroment passed to the config, when it is a function

Basic options:
  --context    The root directory for resolving entry point and stats
                                       [string] [default: The current directory]
  --entry      The entry point                                          [string]
  --watch, -w  Watch the filesystem for changes                        [boolean]
  --debug      Switch loaders to debug mode                            [boolean]
  --devtool    Enable devtool for better debugging experience (Example:
               --devtool eval-cheap-module-source-map)                  [string]
  -d           shortcut for --debug --devtool eval-cheap-module-source-map
               --output-pathinfo                                       [boolean]
  -p           shortcut for --optimize-minimize --define
               process.env.NODE_ENV="production" 

                      [boolean]
  --progress   Print compilation progress in percentage                [boolean]

答案 8 :(得分:3)

添加一堆答案:

使用 ExtendedDefinePlugin 代替DefinePlugin

npm install extended-define-webpack-plugin --save-dev.

ExtendedDefinePlugin使用起来更简单,并记录在案:-) link

因为DefinePlugin 缺乏良好的文档,我想通过说它实际上像c#中的 #DEFINE一样有用。

#if (DEBUG)
        Console.WriteLine("Debugging is enabled.");
#endif

因此,如果您想了解DefinePlugin的工作原理,请阅读c #define doucmentation。 link

答案 9 :(得分:2)

我发现以下解决方案最容易为Webpack 2设置环境变量:

例如,我们有一个webpack设置:

var webpack = require('webpack')

let webpackConfig = (env) => { // Passing envirmonment through
                                // function is important here
    return {
        entry: {
        // entries
        },

        output: {
        // outputs
        },

        plugins: [
        // plugins
        ],

        module: {
        // modules
        },

        resolve: {
        // resolves
        }

    }
};

module.exports = webpackConfig;

在Webpack中添加环境变量:

plugins: [
    new webpack.EnvironmentPlugin({
       NODE_ENV: 'development',
       }),
]

定义插件变量并将其添加到plugins

    new webpack.DefinePlugin({
        'NODE_ENV': JSON.stringify(env.NODE_ENV || 'development')
    }),

现在运行webpack命令时,将env.NODE_ENV作为参数传递:

webpack --env.NODE_ENV=development

// OR

webpack --env.NODE_ENV development

现在,您可以在代码中的任意位置访问NODE_ENV变量。

答案 10 :(得分:1)

我更喜欢将.env文件用于不同的环境。

  1. 使用webpack.dev.config将h1 { margin: 0; } 复制到.env到根文件夹
  2. 使用webpack.prod.config将env.dev复制到.env
  3. 并在代码中

    使用

    env.prod

答案 11 :(得分:1)

自Webpack v4起,只需在Webpack配置中设置mode,即可(通过NODE_ENV)为您设置DefinePluginDocs here.

答案 12 :(得分:1)

现在2020年,我面临着一个相同的问题,但是对于这个旧问题,有很多新答案,请列出其中的一部分:

  • 这是webpack.config.js
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
       name="enrichProxy"
       startOnLoad="true"
       statistics="disable"
       trace="disable"
       transports="http,https">
   <target>
      <inSequence>
         <property name="initial_payload" scope="default">
            <ELEMENT xmlns="">
               <ELEMENT_2>
                  <ELEMENT_3>
                     <ID>173993</ID>
                  </ELEMENT_3>
               </ELEMENT_2>
            </ELEMENT>
         </property>
         <call>
            <endpoint>
               <http uri-template="http://run.mocky.io/v3/7c578a1d-5427-4325-9f00-4ad7bb80dd04"/>
            </endpoint>
         </call>
         <log level="custom">
            <property expression="$body//TEMP/*" name="******"/>
         </log>
         <respond/>
      </inSequence>
   </target>
   <description/>
</proxy>
          

                  

这4种方法仅仅是基本的,我相信还有更多的方法。但是我认为这4way最简单。

答案 13 :(得分:1)

我对 webpack 版本 "webpack": "^4.29.6" 的解决方法非常简单。

//package.json
{
...
 "scripts": {
    "build": "webpack --mode production",
    "start": "webpack-dev-server --open --mode development"
  },
}

您可以在 webpack.config.js 中使用 webpack commnad 传递 --mode 参数

 // webpack.config.json
 module.exports = (env,argv) => {
        return {
           ...
           externals: {
            // global app config object
            config: JSON.stringify({
                apiUrl: (argv.mode==="production") ? '/api' : 'localhost:3002/api'
            })
        }
}

我像这样在我的代码中使用 baseurl

// my api service
import config from 'config';
console.log(config.apiUrl) // like fetch(`${config.apiUrl}/users/user-login`)

答案 14 :(得分:1)

dotenv-webpack

<块引用>

一个安全的 webpack 插件,支持 dotenv 和其他环境变量,并且只公开你选择和使用的内容。

有一些基于 defaults 选项的配置的解决方法来实现这一点,一旦包有 .env.defaults 文件作为环境变量的初始值,您可以将它用于 development 并让 { {1}} 用于您的制作。

用法

  • 安装软件包
.env
  • 创建一个 npm install dotenv-webpack --save-dev 文件
.env.defaults
  • 创建一个 API_URL='dev_url/api/' 文件,将其留空,让 .env 工作,在您的部署过程中更新它
  • 配置 defaults - webpack
webpack.config.js
  • 开发环境测试new Dotenv({ defaults: true })
file.js
  • 在构建时,更新空的 console.log(process.env.API_URL) // Outputs: dev_url/api/ 文件
.env

dotenv-webpack 将使用它来覆盖 API_URL='prod_url/api/'

  • 产品环境测试env.defaults
file.js

dotenv-webpack
dotenv-defaults

答案 15 :(得分:0)

这是一种对我有用的方法,并允许我通过重用json文件来保存环境变量DRY。

let config = require('./settings.json');
if (__PROD__) {
  config = require('./settings-prod.json');
}

const envVars = {};
Object.keys(config).forEach((key) => {
  envVars[key] = JSON.stringify(config[key]);
});

new webpack.DefinePlugin({
  'process.env': envVars
}),

答案 16 :(得分:0)

我不是...的忠实粉丝

new webpack.DefinePlugin({
  'process.env': envVars
}),

...因为它不提供任何类型的安全性。相反,最终您会增加秘密内容,除非您向gitignore add‍♀️添加Webpack,否则会有更好的解决方案。

基本上,使用此配置,一旦您编译了代码,所有进程环境变量将从整个代码中删除,因此不会有单个process.env.VAR,这要归功于babel插件transform-inline-environment-variables PS:如果您不希望遇到很多未定义的事情,请确保在webpack调用babel-loader之前先调用env.js,这就是为什么它是webpack调用的第一件事。 babel.config.js文件中的vars数组必须与env.js上的对象匹配。现在只有一件要做的事情。 添加一个.env文件,将您所有的env变量放置在该文件中,该文件必须位于项目的根目录或随意将其添加到您想要的任何位置,只需确保在env.js文件上设置相同的位置并将其添加到gitignore

const dotFiles = ['.env'].filter(Boolean);

if (existsSync(dotFiles)) {
    require("dotenv-expand")(require("dotenv").config((dotFiles)));
}

如果您想查看整个babel + webpack + ts,请听 https://github.com/EnetoJara/Node-typescript-babel-webpack.git

相同的逻辑适用于做出反应,所有其他?

config
---webpack.js
---env.js
src
---source code world
.env
bunch of dotFiles

env.js

"use strict";
/***
I took the main idea from CRA, but mine is more cooler xD
*/
const {realpathSync, existsSync} = require('fs');
const {resolve, isAbsolute, delimiter} = require('path');

const NODE_ENV = process.env.NODE_ENV || "development";

const appDirectory = realpathSync(process.cwd());

if (typeof NODE_ENV !== "string") {
    throw new Error("falle and stuff");
}

const dotFiles = ['.env'].filter(Boolean);

if (existsSync(dotFiles)) {
    require("dotenv-expand")(require("dotenv").config((dotFiles)));
}

process.env.NODE_PATH = (process.env.NODE_PATH || "")
    .split(delimiter)
    .filter(folder => folder && isAbsolute(folder))
    .map(folder => resolve(appDirectory, folder))
    .join(delimiter);

const ENETO_APP = /^ENETO_APP_/i;

module.exports = (function () {
    const raw = Object.keys ( process.env )
        .filter ( key => ENETO_APP.test ( key ) )
        .reduce ( ( env, key ) => {
                env[ key ] = process.env[ key ];
                return env;
            },
            {
                BABEL_ENV: process.env.ENETO_APP_BABEL_ENV,
                ENETO_APP_DB_NAME: process.env.ENETO_APP_DB_NAME,
                ENETO_APP_DB_PASSWORD: process.env.ENETO_APP_DB_PASSWORD,
                ENETO_APP_DB_USER: process.env.ENETO_APP_DB_USER,
                GENERATE_SOURCEMAP: process.env.ENETO_APP_GENERATE_SOURCEMAP,
                NODE_ENV: process.env.ENETO_APP_NODE_ENV,
                PORT: process.env.ENETO_APP_PORT,
                PUBLIC_URL: "/"
            } );

    const stringyField = {
        "process.env": Object.keys(raw).reduce((env, key)=> {
            env[key]=JSON.stringify(raw[key]);
            return env;
        },{}),

    };

    return {
        raw, stringyField
    }
})();

没有插件巨魔的webpack文件

"use strict";

require("core-js");
require("./env.js");

const path = require("path");
const nodeExternals = require("webpack-node-externals");

module.exports = env => {
    return {
        devtool: "source-map",
        entry: path.join(__dirname, '../src/dev.ts'),
        externals: [nodeExternals()],
        module: {
            rules: [
                {
                    exclude: /node_modules/,
                    test: /\.ts$/,
                    use: [
                        {
                            loader: "babel-loader",
                        },
                        {
                            loader: "ts-loader"
                        }
                    ],
                },
                {
                    test: /\.(png|jpg|gif)$/,
                    use: [
                        {
                            loader: "file-loader",
                        },
                    ],
                },
            ],
        },
        node: {
            __dirname: false,
            __filename: false,
        },
        optimization: {
            splitChunks: {
                automaticNameDelimiter: "_",
                cacheGroups: {
                    vendor: {
                        chunks: "initial",
                        minChunks: 2,
                        name: "vendor",
                        test: /[\\/]node_modules[\\/]/,
                    },
                },
            },
        },
        output: {
            chunkFilename: "main.chunk.js",
            filename: "name-bundle.js",
            libraryTarget: "commonjs2",
        },
        plugins: [],
        resolve: {
            extensions: ['.ts', '.js']
        }   ,
        target: "node"
    };
};

babel.config.js

module.exports = api => {

    api.cache(() => process.env.NODE_ENV);

    return {

        plugins: [
            ["@babel/plugin-proposal-decorators", { legacy: true }],
            ["@babel/plugin-transform-classes", {loose: true}],
            ["@babel/plugin-external-helpers"],
            ["@babel/plugin-transform-runtime"],
            ["@babel/plugin-transform-modules-commonjs"],
            ["transform-member-expression-literals"],
            ["transform-property-literals"],
            ["@babel/plugin-transform-reserved-words"],
            ["@babel/plugin-transform-property-mutators"],
            ["@babel/plugin-transform-arrow-functions"],
            ["@babel/plugin-transform-block-scoped-functions"],
            [
                "@babel/plugin-transform-async-to-generator",
                {
                    method: "coroutine",
                    module: "bluebird",
                },
            ],
            ["@babel/plugin-proposal-async-generator-functions"],
            ["@babel/plugin-transform-block-scoping"],
            ["@babel/plugin-transform-computed-properties"],
            ["@babel/plugin-transform-destructuring"],
            ["@babel/plugin-transform-duplicate-keys"],
            ["@babel/plugin-transform-for-of"],
            ["@babel/plugin-transform-function-name"],
            ["@babel/plugin-transform-literals"],
            ["@babel/plugin-transform-object-super"],
            ["@babel/plugin-transform-shorthand-properties"],
            ["@babel/plugin-transform-spread"],
            ["@babel/plugin-transform-template-literals"],
            ["@babel/plugin-transform-exponentiation-operator"],
            ["@babel/plugin-proposal-object-rest-spread"],
            ["@babel/plugin-proposal-do-expressions"],
            ["@babel/plugin-proposal-export-default-from"],
            ["@babel/plugin-proposal-export-namespace-from"],
            ["@babel/plugin-proposal-logical-assignment-operators"],
            ["@babel/plugin-proposal-throw-expressions"],
            [
                "transform-inline-environment-variables",
                {
                    include: [
                        "ENETO_APP_PORT",
                        "ENETO_APP_NODE_ENV",
                        "ENETO_APP_BABEL_ENV",
                        "ENETO_APP_DB_NAME",
                        "ENETO_APP_DB_USER",
                        "ENETO_APP_DB_PASSWORD",
                    ],
                },
            ],
        ],
        presets: [["@babel/preset-env",{
            targets: {
                node: "current",
                esmodules: true
            },
            useBuiltIns: 'entry',
            corejs: 2,
            modules: "cjs"
        }],"@babel/preset-typescript"],
    };
};

答案 17 :(得分:-4)

我不知道为什么,但没有人真正提到最简单的解决方案。这适用于nodejs和grunt。对于许多人来说,webpack可能会令人困惑,你可以简单地使用以下行:

process.env.NODE_ENV = 'production';

使用上述解决方案,您不需要使用envify或webpack。有时,简单的硬编码解决方案可能适用于某些人。