I am using the npm
modules grunt env and load-grunt-config in my project. grunt env
handles environment variables for you, while load-grunt-config
handles, well, loads the grunt
configuration for you. You can put your tasks into other files, then load-grunt-config
will bundle them up and have grunt
load & consume them for you. You can also make an aliases.js
file, with tasks you want to combine together into one task, running one after another. It's similar to the grunt.registerTask task in the original Gruntfile.js
. I put all my grunt
tasks inside a separate grunt/
folder under the root folder with the main Gruntfile
, with no extra subfolders, as suggested by the load-grunt-config
README.md on Github. Here is my slimmed-down Gruntfile
:
我在我的项目中使用npm模块grunt env和load-grunt-config。 grunt env为你处理环境变量,而load-grunt-config处理,为你加载grunt配置。你可以把你的任务放到其他文件中,然后load-grunt-config会将它们捆绑起来并加载gurnt并为你消耗它们。您还可以创建一个aliases.js文件,其中包含要组合在一起的任务,一个接一个地运行。它类似于原始Gruntfile.js中的grunt.registerTask任务。我将所有的grunt任务放在根文件夹下的一个单独的grunt /文件夹中,使用主Gruntfile,没有额外的子文件夹,如Github上的load-grunt-config README.md所示。这是我精简的Gruntfile:
module.exports = function(grunt) {
'use strict';
require('time-grunt')(grunt);
// function & property declarations
grunt.initConfig({
pkg: grunt.file.readJSON('package.json')
});
require('load-grunt-config')(grunt, {
init: true,
loadGruntConfig: {
scope: 'devDependencies',
pattern: ['grunt-*', 'time-grunt']
}
});
};
In theory, setting all these files up the correct way for load-grunt-config
to load should be exactly the same as just having a Gruntfile.js
. However, I seem to have run into a little snag. It seems the environment variables set under the env
task do not get set for the subsequent grunt
tasks, but are set by the time node
processes its tasks, in this case an express
server.
理论上,将所有这些文件设置为load-grunt-config加载的正确方法应该与只有Gruntfile.js完全相同。但是,我似乎遇到了一些障碍。似乎在env任务下设置的环境变量不会为后续的grunt任务设置,而是由时间节点处理其任务设置,在本例中为快速服务器。
grunt env
task:
grunt env任务:
module.exports = {
// environment variable values for developers
// creating/maintaining site
dev: {
options: {
add: {
NODE_ENV: 'dev',
MONGO_PORT: 27017,
SERVER_PORT: 3000
}
}
}
};
grunt-shell-spawn task:
// shell command tasks
module.exports = {
// starts up MongoDB server/daemon
mongod: {
command: 'mongod --bind_ip konneka.org --port ' + (process.env.MONGO_PORT || 27017) + ' --dbpath C:/MongoDB/data/db --ipv6',
options: {
async: true, // makes this command asynchronous
stdout: false, // does not print to the console
stderr: true, // prints errors to the console
failOnError: true, // fails this task when it encounters errors
execOptions: {
cwd: '.'
}
}
}
};
grunt express task:
咕噜快递任务:
module.exports = {
// default options
options: {
hostname: '127.0.0.1', // allow connections from localhost
port: (process.env.SERVER_PORT || 3000), // default port
},
prod: {
options: {
livereload: true, // automatically reload server when express pages change
// serverreload: true, // run forever-running server (do not close when finished)
server: path.resolve(__dirname, '../backend/page.js'), // express server file
bases: 'dist/' // watch files in app folder for changes
}
}
};
aliases.js
file (grunt-load-config
's way of combining tasks so they run one after the other):
aliases.js文件(grunt-load-config组合任务的方式,因此它们一个接一个地运行):
module.exports = {
// starts forever-running server with "production" environment
server: ['env:prod', 'shell:mongod', 'express:prod', 'express-keepalive']
};
part of backend/env/prod.js
(environment-specific Express configuration, loaded if NODE_ENV
is set to "prod", modeled after MEAN.JS):
backend / env / prod.js的一部分(特定于环境的Express配置,如果NODE_ENV设置为“prod”,则加载,以MEAN.JS为模型):
'use strict';
module.exports = {
port: process.env.SERVER_PORT || 3001,
dbUrl: process.env.MONGOHQ_URL || process.env.MONGOLAB_URI || 'mongodb://konneka.org:' + (process.env.MONGO_PORT || 27018) + '/mean'
};
part of backend/env/dev.js
(environment-specific Express configuration for dev
environment, loaded if the `NODE_ENV variable is not set or is set to "dev"):
backend / env / dev.js的一部分(dev环境的特定于环境的Express配置,如果`NODE_ENV变量未设置或设置为“dev”则加载):
module.exports = {
port: process.env.SERVER_PORT || 3000,
dbUrl: 'mongodb://konneka.org:' + (process.env.MONGO_PORT || 27017) + '/mean-dev'
};
part of backend/page.js
(my Express configuration page, also modeled after MEAN.JS):
backend / page.js的一部分(我的Express配置页面,也是在MEAN.JS之后建模的):
'use strict';
var session = require('express-session');
var mongoStore = require('connect-mongo')(session);
var express = require('express');
var server = express();
...
// create the database object
var monServer = mongoose.connect(environ.dbUrl);
// create a client-server session, using a MongoDB collection/table to store its info
server.use(session({
resave: true,
saveUninitialized: true,
secret: environ.sessionSecret,
store: new mongoStore({
db: monServer.connections[0].db, // specify the database these sessions will be saved into
auto_reconnect: true
})
}));
...
// listen on port related to environment variable
server.listen(process.env.SERVER_PORT || 3000);
module.exports = server;
When I run grunt server
, I get:
当我运行grunt服务器时,我得到:
$ cd /c/repos/konneka/ && grunt server
Running "env:prod" (env) task
Running "shell:mongod" (shell) task
Running "express:prod" (express) task
Running "express-server:prod" (express-server) task
Web server started on port:3000, hostname: 127.0.0.1 [pid: 3996]
Running "express-keepalive" task
Fatal error: failed to connect to [konneka.org:27018]
Execution Time (2014-08-15 18:05:31 UTC)
loading tasks 38.3s █████████████████████████████████ 79%
express-server:prod 8.7s ████████ 18%
express-keepalive 1.2s ██ 2%
Total 48.3s
Now, I can't seem to get the database connected in the first place, but ignore that for now. Notice that the server is started on port 3000, meaning that during execution of the grunt express:prod
task, SERVER_PORT
is not set so the port gets set to 3000. There are numerous other examples like this, where an environment variable is not set so my app uses the default. However, notice that session
tries to connect to the database on port 27018 (and fails), so MONGO_PORT
does get set eventually.
现在,我似乎无法首先连接数据库,但暂时忽略它。请注意,服务器在端口3000上启动,这意味着在执行grunt express:prod任务期间,未设置SERVER_PORT,因此端口设置为3000.还有许多其他示例,其中未设置环境变量我的应用使用默认值。但是,请注意会话尝试在端口27018上连接到数据库(并且失败),因此最终会设置MONGO_PORT。
If I had just tried the grunt server
task, I could chalk it up to load-grunt-config
running the tasks in parallel instead of one after the other or some other error, but even when I try the tasks one-by-one, such as running grunt env:prod shell:mongod express-server:prod express-keepalive
, I get similar (incorrect) results, so either grunt
or grunt env
run the tasks in parallel, as well, or something else is going on.
如果我刚刚尝试了grunt服务器任务,我可以将它归结为load-grunt-config并行运行任务而不是一个接一个或其他错误,但即使我逐个尝试任务,例如运行grunt env:prod shell:mongod express-server:prod express-keepalive,我得到类似(不正确)的结果,所以grunt或grunt env并行运行任务,或其他正在进行的事情。
What's going on here? Why are the environment variables not set correctly for later grunt
tasks? When are they eventually set, and why then rather than some other time? How can I make them get set for grunt
tasks themselves rather than after, assuming there even is a way?
这里发生了什么?为什么环境变量没有为以后的grunt任务设置正确?他们什么时候最终确定,为什么然后而不是其他时间呢?我怎样才能让它们自己设置为grunt任务而不是之后,假设有一种方法呢?
2 个解决方案
#1
7
The solution is rather obvious once you figure it out, so let's start at the beginning:
一旦你弄明白,解决方案就显而易见了,所以让我们从头开始:
The problem
You're using load-grunt-config
to load a set of modules (objects that define tasks) and combine them into one module (object) and pass it along to Grunt. To better understand what load-grunt-config
is doing, take a moment to read through the source (it's just three files). So, instead of writing:
您正在使用load-grunt-config加载一组模块(定义任务的对象)并将它们组合成一个模块(对象)并将其传递给Grunt。为了更好地理解load-grunt-config正在做什么,请花点时间阅读源代码(它只是三个文件)。所以,而不是写:
// filename: Gruntfile.js
grunt.initConfig({
foo: {
a: {
options: {},
}
},
bar: {
b: {
options: {},
}
}
});
You can write this:
你可以这样写:
// filename: grunt/foo.js
module.exports = {
a: {
options: {},
}
}
// filename: grunt/bar.js
module.exports = {
b: {
options: {},
}
}
// filename: Gruntfile.js
require('load-grunt-config')(grunt);
Basically, this way you can split up a Grunt configuration into multiple files and have it be more "maintainable". But what you'll need to realize is that these two approaches are semantically equivalent. That is, you can expect them to behave the same way.
基本上,通过这种方式,您可以将Grunt配置拆分为多个文件,并使其更具“可维护性”。但是你需要意识到的是,这两种方法在语义上是等价的。也就是说,你可以期望它们的行为方式相同。
Thus, when you write the following*:
因此,当您编写以下*时:
(* I've reduced the problem in an attempt to make this answer a bit more general and to reduce noise. I've excluded things like loading the tasks and extraneous option passing, but the error should still be the same. Also note that I've changed the values of the environment variables because the default was the same as what was being set.)
(*我已经减少了问题,试图使这个答案更加通用并减少噪音。我已经排除了加载任务和无关选项传递之类的东西,但错误应该仍然是相同的。还要注意我已经更改了环境变量的值,因为默认值与设置的值相同。)
// filename: grunt/env.js
module.exports = {
dev: {
options: {
add: {
// These values are different for demo purposes
NODE_ENV: 'dev',
MONGO_PORT: 'dev_mongo_port',
SERVER_PORT: 'dev_server_port'
}
}
}
};
// filename: grunt/shell.js
module.exports = {
mongod: {
command: 'mongod --port ' + (process.env.MONGO_PORT || 27017)
}
};
// filename: grunt/aliases.js
module.exports = {
server: ['env:prod', 'shell:mongod']
};
// filename: Gruntfile.js
module.exports = function (grunt) {
require('load-grunt-config')(grunt);
};
You can consider the above the same as below:
您可以考虑以上相同的内容:
module.exports = function (grunt) {
grunt.initConfig({
env: {
dev: {
options: {
add: {
NODE_ENV: 'dev',
MONGO_PORT: 'dev_mongo_port',
SERVER_PORT: 'dev_server_port'
}
}
}
},
shell: {
mongod: {
command: 'mongod --port ' + (process.env.MONGO_PORT || 27017)
}
}
});
grunt.registerTask('server', ['env:dev', 'shell:mongod']);
};
Now do you see the problem? What command do you expect shell:mongod
to run? The correct answer is:
现在你看到了问题吗?你期望shell有什么命令:mongod运行?正确答案是:
mongod --port 27017
Where what you want to be executed is:
你想要执行的是:
mongo --port dev_mongo_port
The problem is that when (process.env.MONGO_PORT || 27017)
is evaluated the environment variables have not yet been set (i.e. before the env:dev
task has been run).
问题是当评估(process.env.MONGO_PORT || 27017)时,尚未设置环境变量(即在运行env:dev任务之前)。
A solution
Well let's look at a working Grunt configuration before splitting it across multiple files:
好吧,让我们看看一个有效的Grunt配置,然后将它分割成多个文件:
module.exports = function (grunt) {
grunt.initConfig({
env: {
dev: {
options: {
add: {
NODE_ENV: 'dev',
MONGO_PORT: 'dev_mongo_port',
SERVER_PORT: 'dev_server_port'
}
}
}
},
shell: {
mongod: {
command: 'mongod --port ${MONGO_PORT:-27017}'
}
}
});
grunt.registerTask('server', ['env:dev', 'shell:mongod']);
};
Now when you run shell:mongod
, the command will contain ${MONGO_PORT:-27017}
and Bash (or just sh) will look for the environment variable you would have set in the task before it (i.e. env:dev
).
现在当你运行shell:mongod时,该命令将包含$ {MONGO_PORT:-27017},Bash(或只是sh)将查找你在之前的任务中设置的环境变量(即env:dev)。
Okay, that's all well and good for the shell:mongod
task, but what about the other tasks, Express for example?
好吧,这对shell来说还是很好的:mongod任务,但是其他任务呢,例如Express?
You'll need to move away from environment variables (unless you want to set them up before invoking Grunt. Why? Take this Grunt configuration for example:
你需要远离环境变量(除非你想在调用Grunt之前设置它们。为什么?以这个Grunt配置为例:
module.exports = function (grunt) {
grunt.initConfig({
env: {
dev: {
options: {
add: {
NODE_ENV: 'dev',
MONGO_PORT: 'dev_mongo_port',
SERVER_PORT: 'dev_server_port'
}
}
}
},
express: {
options: {
hostname: '127.0.0.1'
port: (process.env.SERVER_PORT || 3000)
},
prod: {
options: {
livereload: true
server: path.resolve(__dirname, '../backend/page.js'),
bases: 'dist/'
}
}
}
});
grunt.registerTask('server', ['env:dev', 'express:prod']);
};
What port will the express:prod
task configuration contain? 3000
. What you need is for it to reference the value you've defined in the above task. How you do this is up to you. You could:
express:prod任务配置包含哪些端口? 3000.您需要的是它引用您在上述任务中定义的值。你如何做到这一点取决于你。你可以:
-
Separate the
env
configuration and reference its values分离env配置并引用其值
module.exports = function (grunt) { grunt.config('env', { dev: { options: { add: { NODE_ENV: 'dev', MONGO_PORT: 'dev_mongo_port', SERVER_PORT: 'dev_server_port' } } } }); grunt.config('express', { options: { hostname: '127.0.0.1' port: '<%= env.dev.options.add.SERVER_PORT %>' } }); grunt.registerTask('server', ['env:dev', 'express:prod']); };
But you'll notice that the semantics of the
env
task don't hold up here due to it no longer representing a task's configuration. You could use an object of your own design:但是你会注意到env任务的语义由于它不再代表任务的配置而不能在这里停留。您可以使用自己设计的对象:
module.exports = function (grunt) { grunt.config('env', { dev: { NODE_ENV: 'dev', MONGO_PORT: 'dev_mongo_port', SERVER_PORT: 'dev_server_port' } }); grunt.config('express', { options: { hostname: '127.0.0.1' port: '<%= env.dev.SERVER_PORT %>' } }); grunt.registerTask('server', ['env:dev', 'express:prod']); };
-
Pass
grunt
an argument to specify what config it should use传递一个参数来指定它应该使用的配置
- Have multiple configuration files (e.g.
Gruntfile.js.dev
andGruntfile.js.prod
) and rename them as needed - Read a development configuration file (e.g.
grunt.file.readJSON('config.development.json')
) if it exists and fall back to a production configuration file if it doesn't exist - Some better way not listed here
有多个配置文件(例如Gruntfile.js.dev和Gruntfile.js.prod)并根据需要重命名它们
读取开发配置文件(例如grunt.file.readJSON('config.development.json'))(如果存在)并回退到生产配置文件(如果它不存在)
这里没有列出更好的方法
But all of the above should achieve the same end result.
但是以上所有都应该达到同样的最终结果。
#2
4
This seems to be the essence of what you are trying to do, and it works for me. The important part was what I mentioned in my comment -- chaining the environment task before running the other tasks.
这似乎是你想要做的事情的本质,它对我有用。重要的部分是我在评论中提到的 - 在运行其他任务之前链接环境任务。
Gruntfile.js
module.exports = function(grunt) {
// Do grunt-related things in here
grunt.loadNpmTasks('grunt-env');
grunt.initConfig({
env: {
dev: {
PROD : 'http://production.server'
}
}
});
grunt.registerTask('printEnv', 'prints a message with an env var', function() { console.log('Env var in subsequent grunt task: ' + process.env.PROD) } );
grunt.registerTask('prod', ['env:dev', 'printEnv']);
};
Output of grunt prod
输出grunt prod
Running "env:dev" (env) task
Running "printEnv" task
Env var in subsequent grunt task: http://production.server
Done, without errors.
#1
7
The solution is rather obvious once you figure it out, so let's start at the beginning:
一旦你弄明白,解决方案就显而易见了,所以让我们从头开始:
The problem
You're using load-grunt-config
to load a set of modules (objects that define tasks) and combine them into one module (object) and pass it along to Grunt. To better understand what load-grunt-config
is doing, take a moment to read through the source (it's just three files). So, instead of writing:
您正在使用load-grunt-config加载一组模块(定义任务的对象)并将它们组合成一个模块(对象)并将其传递给Grunt。为了更好地理解load-grunt-config正在做什么,请花点时间阅读源代码(它只是三个文件)。所以,而不是写:
// filename: Gruntfile.js
grunt.initConfig({
foo: {
a: {
options: {},
}
},
bar: {
b: {
options: {},
}
}
});
You can write this:
你可以这样写:
// filename: grunt/foo.js
module.exports = {
a: {
options: {},
}
}
// filename: grunt/bar.js
module.exports = {
b: {
options: {},
}
}
// filename: Gruntfile.js
require('load-grunt-config')(grunt);
Basically, this way you can split up a Grunt configuration into multiple files and have it be more "maintainable". But what you'll need to realize is that these two approaches are semantically equivalent. That is, you can expect them to behave the same way.
基本上,通过这种方式,您可以将Grunt配置拆分为多个文件,并使其更具“可维护性”。但是你需要意识到的是,这两种方法在语义上是等价的。也就是说,你可以期望它们的行为方式相同。
Thus, when you write the following*:
因此,当您编写以下*时:
(* I've reduced the problem in an attempt to make this answer a bit more general and to reduce noise. I've excluded things like loading the tasks and extraneous option passing, but the error should still be the same. Also note that I've changed the values of the environment variables because the default was the same as what was being set.)
(*我已经减少了问题,试图使这个答案更加通用并减少噪音。我已经排除了加载任务和无关选项传递之类的东西,但错误应该仍然是相同的。还要注意我已经更改了环境变量的值,因为默认值与设置的值相同。)
// filename: grunt/env.js
module.exports = {
dev: {
options: {
add: {
// These values are different for demo purposes
NODE_ENV: 'dev',
MONGO_PORT: 'dev_mongo_port',
SERVER_PORT: 'dev_server_port'
}
}
}
};
// filename: grunt/shell.js
module.exports = {
mongod: {
command: 'mongod --port ' + (process.env.MONGO_PORT || 27017)
}
};
// filename: grunt/aliases.js
module.exports = {
server: ['env:prod', 'shell:mongod']
};
// filename: Gruntfile.js
module.exports = function (grunt) {
require('load-grunt-config')(grunt);
};
You can consider the above the same as below:
您可以考虑以上相同的内容:
module.exports = function (grunt) {
grunt.initConfig({
env: {
dev: {
options: {
add: {
NODE_ENV: 'dev',
MONGO_PORT: 'dev_mongo_port',
SERVER_PORT: 'dev_server_port'
}
}
}
},
shell: {
mongod: {
command: 'mongod --port ' + (process.env.MONGO_PORT || 27017)
}
}
});
grunt.registerTask('server', ['env:dev', 'shell:mongod']);
};
Now do you see the problem? What command do you expect shell:mongod
to run? The correct answer is:
现在你看到了问题吗?你期望shell有什么命令:mongod运行?正确答案是:
mongod --port 27017
Where what you want to be executed is:
你想要执行的是:
mongo --port dev_mongo_port
The problem is that when (process.env.MONGO_PORT || 27017)
is evaluated the environment variables have not yet been set (i.e. before the env:dev
task has been run).
问题是当评估(process.env.MONGO_PORT || 27017)时,尚未设置环境变量(即在运行env:dev任务之前)。
A solution
Well let's look at a working Grunt configuration before splitting it across multiple files:
好吧,让我们看看一个有效的Grunt配置,然后将它分割成多个文件:
module.exports = function (grunt) {
grunt.initConfig({
env: {
dev: {
options: {
add: {
NODE_ENV: 'dev',
MONGO_PORT: 'dev_mongo_port',
SERVER_PORT: 'dev_server_port'
}
}
}
},
shell: {
mongod: {
command: 'mongod --port ${MONGO_PORT:-27017}'
}
}
});
grunt.registerTask('server', ['env:dev', 'shell:mongod']);
};
Now when you run shell:mongod
, the command will contain ${MONGO_PORT:-27017}
and Bash (or just sh) will look for the environment variable you would have set in the task before it (i.e. env:dev
).
现在当你运行shell:mongod时,该命令将包含$ {MONGO_PORT:-27017},Bash(或只是sh)将查找你在之前的任务中设置的环境变量(即env:dev)。
Okay, that's all well and good for the shell:mongod
task, but what about the other tasks, Express for example?
好吧,这对shell来说还是很好的:mongod任务,但是其他任务呢,例如Express?
You'll need to move away from environment variables (unless you want to set them up before invoking Grunt. Why? Take this Grunt configuration for example:
你需要远离环境变量(除非你想在调用Grunt之前设置它们。为什么?以这个Grunt配置为例:
module.exports = function (grunt) {
grunt.initConfig({
env: {
dev: {
options: {
add: {
NODE_ENV: 'dev',
MONGO_PORT: 'dev_mongo_port',
SERVER_PORT: 'dev_server_port'
}
}
}
},
express: {
options: {
hostname: '127.0.0.1'
port: (process.env.SERVER_PORT || 3000)
},
prod: {
options: {
livereload: true
server: path.resolve(__dirname, '../backend/page.js'),
bases: 'dist/'
}
}
}
});
grunt.registerTask('server', ['env:dev', 'express:prod']);
};
What port will the express:prod
task configuration contain? 3000
. What you need is for it to reference the value you've defined in the above task. How you do this is up to you. You could:
express:prod任务配置包含哪些端口? 3000.您需要的是它引用您在上述任务中定义的值。你如何做到这一点取决于你。你可以:
-
Separate the
env
configuration and reference its values分离env配置并引用其值
module.exports = function (grunt) { grunt.config('env', { dev: { options: { add: { NODE_ENV: 'dev', MONGO_PORT: 'dev_mongo_port', SERVER_PORT: 'dev_server_port' } } } }); grunt.config('express', { options: { hostname: '127.0.0.1' port: '<%= env.dev.options.add.SERVER_PORT %>' } }); grunt.registerTask('server', ['env:dev', 'express:prod']); };
But you'll notice that the semantics of the
env
task don't hold up here due to it no longer representing a task's configuration. You could use an object of your own design:但是你会注意到env任务的语义由于它不再代表任务的配置而不能在这里停留。您可以使用自己设计的对象:
module.exports = function (grunt) { grunt.config('env', { dev: { NODE_ENV: 'dev', MONGO_PORT: 'dev_mongo_port', SERVER_PORT: 'dev_server_port' } }); grunt.config('express', { options: { hostname: '127.0.0.1' port: '<%= env.dev.SERVER_PORT %>' } }); grunt.registerTask('server', ['env:dev', 'express:prod']); };
-
Pass
grunt
an argument to specify what config it should use传递一个参数来指定它应该使用的配置
- Have multiple configuration files (e.g.
Gruntfile.js.dev
andGruntfile.js.prod
) and rename them as needed - Read a development configuration file (e.g.
grunt.file.readJSON('config.development.json')
) if it exists and fall back to a production configuration file if it doesn't exist - Some better way not listed here
有多个配置文件(例如Gruntfile.js.dev和Gruntfile.js.prod)并根据需要重命名它们
读取开发配置文件(例如grunt.file.readJSON('config.development.json'))(如果存在)并回退到生产配置文件(如果它不存在)
这里没有列出更好的方法
But all of the above should achieve the same end result.
但是以上所有都应该达到同样的最终结果。
#2
4
This seems to be the essence of what you are trying to do, and it works for me. The important part was what I mentioned in my comment -- chaining the environment task before running the other tasks.
这似乎是你想要做的事情的本质,它对我有用。重要的部分是我在评论中提到的 - 在运行其他任务之前链接环境任务。
Gruntfile.js
module.exports = function(grunt) {
// Do grunt-related things in here
grunt.loadNpmTasks('grunt-env');
grunt.initConfig({
env: {
dev: {
PROD : 'http://production.server'
}
}
});
grunt.registerTask('printEnv', 'prints a message with an env var', function() { console.log('Env var in subsequent grunt task: ' + process.env.PROD) } );
grunt.registerTask('prod', ['env:dev', 'printEnv']);
};
Output of grunt prod
输出grunt prod
Running "env:dev" (env) task
Running "printEnv" task
Env var in subsequent grunt task: http://production.server
Done, without errors.