I'm following these instructions based on this project (the official Vue Webpack template).
This is what I did:
package.js:
"scripts": {
"dev": "node build/dev-server.js",
"dev-alt": "node build/dev-server.js && set arg=alt&&webpack"
},
webpack.base.config.js:
// npm run dev-alt in the terminal
console.log('ARGS:', process.env.arg)
However ARGS: outputs undefined.
What the correct way to do this?
With Webpack 5.x and above you can no longer pass custom arguments to Webpack like --myarg=val. But you can still pass the supported arguments like --mode=production.
So what's the solution for custom args? Instead we need to write it like this, using the new --env parameter.
"build-project": webpack --mode=production --env myarg=val --env otherarg=val
Note that the custom arguments no longer start with -- after we put --env ahead of them. You'll need to put --env ahead of each custom key/value pair you need to define.
You'll also need to modify your Webpack config to export a function, rather than an object.
See this example code, taken from the docs.
const path = require('path');
module.exports = (env) => {
// Use env.<YOUR VARIABLE> here:
console.log('NODE_ENV: ', env.NODE_ENV); // 'local'
console.log('Production: ', env.production); // true
return {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
};
};
Pass webpack arguments with --key=value in package.json
"scripts": {
"build": "webpack --mode=production --browser=firefox",
}
Access argv in webpack.config.js like this
module.exports = (env, argv) => {
if (argv.mode == "development") {
}
if (argv.browser == "firefox") {
}
};
You can pass whatever arguments you want by:
node my-script.js --myArgs thisIsTheValue
In my-script.js you can retrieve arguments by:
function getArg(key, defaultVal) {
var index = process.argv.indexOf(key),
next = process.argv[index + 1];
defaultVal = defaultVal || null;
return (index < 0) ? defaultVal : (!next || next[0] === "-") ? true : next;
}
var theArgsIWant = getArg('--myArgs', 'this is the default if argument not found');
From the article you described:
"scripts": {
"webpack-quizMaker": "set arg=quizMaker&&webpack",
"webpack-quiz": "set arg=quiz&&webpack"
}
These scritps are doing 2 things:
They are setting an environment variable in a way that only works on Windows if you're not using PowerShell. It's recommend to use cross-env here.
They are running webpack after setting the envinronment variable.
Then, inside the webpack configuration, they are reading the environment variable:
if (process.env.arg == "quiz") {
// do your thing
}
if (process.env.arg == "quizMaker") {
// do your thing
};
I recommend that you install cross-env
npm install --save-dev cross-env
And replace the scripts with this:
"scripts": {
"webpack-quizMaker": "cross-env arg=\"quizMaker\" webpack",
"webpack-quiz": "set arg=\"quiz\" webpack"
}
No need for && anymore because cross-env will call the specified command (webpack) after setting the env variable.
You can try this:
const onlyJS = process.argv.some(argument => argument === 'your argument');
Related
What I have been trying to do is to generate and run migrations with typeorm in the nest.js app within Nx.dev Monorepo.
But cannot find a way to do so.
My mono-repo looks like this
mono-repo structure
My database configurations look like this
database configurations
And this is how I have initialized my connection in the app.module.ts file
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
useClass: DatabaseConfig
}),
I just wanted to know the way to generate and up the migrations.
Thanks and regards
In order to run typeorm cli in my Nx monorepo, I have added following target in my project.json:
"typeorm": {
"executor": "nx:run-commands",
"outputs": [],
"options": {
"command": "TS_NODE_PROJECT=apps/web-api/tsconfig.app.json ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli --config ./apps/web-api/src/database/cli.ts",
"cwd": "."
}
},
where cli.ts returns DataSourceOptions in my command line configuration.
Inside I have following configuration for migrations options:
migrations: [path.join(__dirname, 'migrations', '*.[tj]s')],
cli: {
migrationsDir: path.join(__dirname, 'migrations')
},
I execute it with following package.json script:
"migration:generate:web-api": "nx typeorm --project=web-api -- migration:generate -n",
In order to run migrations, I have added webpack configuration:
const glob = require('glob');
module.exports = (config, context) => {
if (config.mode === 'production') {
config.optimization = {
minimize: false,
};
const sourcePaths = ['apps/web-api/src/database/migrations/**/*.[tj]s'];
const additionalEntries = sourcePaths
.flatMap((entryPath) => glob.sync(entryPath, { absolute: false }))
.reduce((previous, current) => {
const filename = current.split('src/')[1];
previous[filename] = current;
return previous;
}, {});
config.entry = {
...config.entry,
...additionalEntries,
};
}
return config;
};
and configured my build target to use it with:
"build": {
...
"options": {
...
"webpackConfig": "apps/web-api/webpack.config.js",
}
}
As far as I know and as far as it's relevant, there is 2 ways to run project on Windows 10 machine, while passing variables:
NODE_ENV=production && npm run dev
npm run prod
What's going on here?.. Why first example runs smoothly, while the second - returns undefined?..
What I get with second example is currentEnv = "production", but exportableEnvName = undefined.
Any ideas how to solve it? And why it happens? Thanks!
P.S. I would prefer in not using other packages as a solution.
Code example:
config.js
const environments = {};
environments.dev = {
httpPort: 3000,
httpsPort: 3001,
}
environments.production = {
httpPort: 5000,
httpsPort: 5001,
}
const currentEnv = typeof process.env.NODE_ENV === 'string' ? process.env.NODE_ENV.toLowerCase() : '';
const exportableEnvName = typeof environments[currentEnv] === 'object' ? currentEnv : 'dev';
module.exports = environments[exportableEnvName];
package.json
{
"scripts": {
"dev": "node .",
"prod": "SET NODE_ENV=production && node ."
},
}
I am currently learning to use next.js in my project which is based on 'create-react-app'. I am getting trouble on setting environment variables as .env.development, .env.staging and .env.production.
I have tried two different way. First approach did not work at all and using second approach I can access the environment variables but it creates infinite loop. Here is the setup I tried
First Approach
.env.development
REACT_APP_API_ENDPOINT=http://localhost:8000
constants/urls.js
console.log("process env", process.env); // {}
export const API_ENDPOINT = process.env.REACT_APP_API_ENDPOINT;
next.config.js
module.exports = withCSS({
cssModules: true,
});
module.exports = withPlugins([[withImages]]);
package.json
"scripts": {
"dev": "NODE_PATH=. dotenv -e .env.development next",
"build": "NODE_PATH=. dotenv -e .env.production next build",
"build:staging": "dotenv -e .env.staging next build",
"start": "next start"
},
Second Approach
.env.development
REACT_APP_API_ENDPOINT=http://localhost:8000
constants/urls.js
console.log("process env", process.env); // {}
export const API_ENDPOINT = process.env.REACT_APP_API_ENDPOINT;
next.config.js
const nextRuntimeDotenv = require("next-runtime-dotenv");
const withConfig = nextRuntimeDotenv({});
const nextConfig = {
poweredByHeader: false,
serverRuntimeConfig: {
NODE_ENV: process.env.NODE_ENV,
},
publicRuntimeConfig: {
NODE_ENV: process.env.NODE_ENV,
API_ENDPOINT: process.env.REACT_APP_API_ENDPOINT || "http://localhost:3000",
},
};
// the reason behind using multiple module.exports is that when wrapping withCss inside
// withPlugins, the css did not work. It instead gives warning that css is disabled
module.exports = withCSS({
cssModules: true,
});
module.exports = withConfig(withPlugins([[withImages]], nextConfig));
This approach creates infinite loop.
I'm trying to use a node process to kick off an interactive docker session then automate some commands to it:
var spawn = require('pty.js').spawn;
var proc = spawn('docker', [ 'run', '-i', '-t', 'mycontainer' ], {
name: 'test',
rows: 30,
cols: 200,
cwd: process.env.HOME,
env: process.env
});
proc.on('data', function (data) {
console.log(data);
});
proc.write('cd /tmp');
proc.write('nvm install 0.10\r');
proc.write('npm install');
This seems to work, the only issue is it seems like it's just writing in all the commands and firing them. I don't seem to have any control over catching the output or errors of individual commands.
I'm curious if there's a better way to approach this?
You can pipe streams to this process, however it is not advised to do so.
const { pipeline } = require('stream');
const { spawn } = require('node-pty')
const proc = spawn('docker', ['run', '--rm', '-ti', 'alpine', '/bin/sh'], {
name: 'xterm-color',
cwd: process.env.HOME,
env: process.env,
encoding: null,
});
pipeline(process.stdin, proc, (err) => err && console.warn(err.message))
pipeline(proc, process.stdout, (err) => err && console.warn(err.message))
The maintainer have suggested to not use pty in like a stream. It's simply a matter of changing the pipeline for something like this.
(async (stream) => {
for await (const chunk of stream) {
proc.write(chunk.toString())
}
})(process.stdin).catch(console.warn)
The gist is that we should pass string into the write function. We also should expect string as its output. Therefore, we should not set any encoding in the object so that it by default outputs utf8 string.
Regarding your initial question. proc.write('ls\r') is the correct way of doing it. Note the trailing \r to virtually press enter. Just like in a normal terminal, when you execute a command, you cannot fire a second one simultaneously. The commands will just queue up and run one after another.
Input:
const { spawn } = require('node-pty')
const proc = spawn('docker', ['run', '--rm', '-ti', '--network=host', 'node', '/bin/sh'], {
name: 'xterm-color',
cwd: process.env.HOME,
env: process.env,
});
proc.write('npm init -y\r')
proc.write('npm i eslint\r')
proc.write('ls node_modules /\r')
const disposable = proc.onData((text) => process.stdout.write(text))
const exitDisposable = proc.onExit(() => {
disposable.dispose()
exitDisposable.dispose()
})
Output:
npm i eslint
ls node_modules /
# Wrote to /package.json:
{
"name": "",
"version": "1.0.0",
"description": "",
"main": "index.js",
"directories": {
"lib": "lib"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN #1.0.0 No description
npm WARN #1.0.0 No repository field.
+ eslint#7.1.0
added 136 packages from 82 contributors and audited 136 packages in 9.461s
9 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
# /:
bin etc lib64 node_modules package.json run sys var
boot home media opt proc sbin tmp
dev lib mnt package-lock.json root srv usr
node_modules:
#babel is-extglob
#types is-fullwidth-code-point
...
...
#
You see it wrote ls before npm install was completed but it ran afterwards.
Also note that I used -ti instead of just -t for the docker args.
Looking through the source for the pty.js module, it is clear that your proc.write is really the standard Node net.Socket.write -- https://nodejs.org/api/net.html#net_socket_write_data_encoding_callback
In short, yes, you are just spamming the commands to the socket. You need to wait for each command to finish before executing the next. Thus, you'll need to use the callback parameter of .write to determine when a command has finished and then proceed from there. Something like this may work:
// this is a quick and dirty hack
let cmdcount = 0;
function submitcmd() {
switch (cmdcount) {
case 0:
proc.write('nvm install 0.10\r', 'utf8', submitcmd);
break;
case 1:
proc.write('npm install', 'utf8', submitcmd);
break;
}
cmdcount += 1;
}
proc.write('cd /tmp', 'utf8', submitcmd);
Normally in Gulp tasks look like this:
gulp.task('my-task', function() {
return gulp.src(options.SCSS_SOURCE)
.pipe(sass({style:'nested'}))
.pipe(autoprefixer('last 10 version'))
.pipe(concat('style.css'))
.pipe(gulp.dest(options.SCSS_DEST));
});
Is it possible to pass a command line flag to gulp (that's not a task) and have it run tasks conditionally based on that? For instance
$ gulp my-task -a 1
And then in my gulpfile.js:
gulp.task('my-task', function() {
if (a == 1) {
var source = options.SCSS_SOURCE;
} else {
var source = options.OTHER_SOURCE;
}
return gulp.src(source)
.pipe(sass({style:'nested'}))
.pipe(autoprefixer('last 10 version'))
.pipe(concat('style.css'))
.pipe(gulp.dest(options.SCSS_DEST));
});
Gulp doesn't offer any kind of util for that, but you can use one of the many command args parsers. I like yargs. Should be:
var argv = require('yargs').argv;
gulp.task('my-task', function() {
return gulp.src(argv.a == 1 ? options.SCSS_SOURCE : options.OTHER_SOURCE)
.pipe(sass({style:'nested'}))
.pipe(autoprefixer('last 10 version'))
.pipe(concat('style.css'))
.pipe(gulp.dest(options.SCSS_DEST));
});
You can also combine it with gulp-if to conditionally pipe the stream, very useful for dev vs. prod building:
var argv = require('yargs').argv,
gulpif = require('gulp-if'),
rename = require('gulp-rename'),
uglify = require('gulp-uglify');
gulp.task('my-js-task', function() {
gulp.src('src/**/*.js')
.pipe(concat('out.js'))
.pipe(gulpif(argv.production, uglify()))
.pipe(gulpif(argv.production, rename({suffix: '.min'})))
.pipe(gulp.dest('dist/'));
});
And call with gulp my-js-task or gulp my-js-task --production.
Edit
gulp-util is deprecated and should be avoid, so it's recommended to use minimist instead, which gulp-util already used.
So I've changed some lines in my gulpfile to remove gulp-util:
var argv = require('minimist')(process.argv.slice(2));
gulp.task('styles', function() {
return gulp.src(['src/styles/' + (argv.theme || 'main') + '.scss'])
…
});
Original
In my project I use the following flag:
gulp styles --theme literature
Gulp offers an object gulp.env for that. It's deprecated in newer versions, so you must use gulp-util for that. The tasks looks like this:
var util = require('gulp-util');
gulp.task('styles', function() {
return gulp.src(['src/styles/' + (util.env.theme ? util.env.theme : 'main') + '.scss'])
.pipe(compass({
config_file: './config.rb',
sass : 'src/styles',
css : 'dist/styles',
style : 'expanded'
}))
.pipe(autoprefixer('last 2 version', 'safari 5', 'ie 8', 'ie 9', 'ff 17', 'opera 12.1', 'ios 6', 'android 4'))
.pipe(livereload(server))
.pipe(gulp.dest('dist/styles'))
.pipe(notify({ message: 'Styles task complete' }));
});
The environment setting is available during all subtasks. So I can use this flag on the watch task too:
gulp watch --theme literature
And my styles task also works.
Ciao
Ralf
Here's a quick recipe I found:
gulpfile.js
var gulp = require('gulp');
// npm install gulp yargs gulp-if gulp-uglify
var args = require('yargs').argv;
var gulpif = require('gulp-if');
var uglify = require('gulp-uglify');
var isProduction = args.env === 'production';
gulp.task('scripts', function() {
return gulp.src('**/*.js')
.pipe(gulpif(isProduction, uglify())) // only minify if production
.pipe(gulp.dest('dist'));
});
CLI
gulp scripts --env production
Original Ref (not available anymore): https://github.com/gulpjs/gulp/blob/master/docs/recipes/pass-params-from-cli.md
Alternative with minimist
From Updated Ref: https://github.com/gulpjs/gulp/blob/master/docs/recipes/pass-arguments-from-cli.md
gulpfile.js
// npm install --save-dev gulp gulp-if gulp-uglify minimist
var gulp = require('gulp');
var gulpif = require('gulp-if');
var uglify = require('gulp-uglify');
var minimist = require('minimist');
var knownOptions = {
string: 'env',
default: { env: process.env.NODE_ENV || 'production' }
};
var options = minimist(process.argv.slice(2), knownOptions);
gulp.task('scripts', function() {
return gulp.src('**/*.js')
.pipe(gulpif(options.env === 'production', uglify())) // only minify if production
.pipe(gulp.dest('dist'));
});
CLI
gulp scripts --env production
There's a very simple way to do on/off flags without parsing the arguments. gulpfile.js is just a file that's executed like any other, so you can do:
var flags = {
production: false
};
gulp.task('production', function () {
flags.production = true;
});
And use something like gulp-if to conditionally execute a step
gulp.task('build', function () {
gulp.src('*.html')
.pipe(gulp_if(flags.production, minify_html()))
.pipe(gulp.dest('build/'));
});
Executing gulp build will produce a nice html, while gulp production build will minify it.
If you've some strict (ordered!) arguments, then you can get them simply by checking process.argv.
var args = process.argv.slice(2);
if (args[0] === "--env" && args[1] === "production");
Execute it: gulp --env production
...however, I think that this is tooo strict and not bulletproof! So, I fiddled a bit around... and ended up with this utility function:
function getArg(key) {
var index = process.argv.indexOf(key);
var next = process.argv[index + 1];
return (index < 0) ? null : (!next || next[0] === "-") ? true : next;
}
It eats an argument-name and will search for this in process.argv. If nothing was found it spits out null. Otherwise if their is no next argument or the next argument is a command and not a value (we differ with a dash) true gets returned. (That's because the key exist, but there's just no value). If all the cases before will fail, the next argument-value is what we get.
> gulp watch --foo --bar 1337 -boom "Foo isn't equal to bar."
getArg("--foo") // => true
getArg("--bar") // => "1337"
getArg("-boom") // => "Foo isn't equal to bar."
getArg("--404") // => null
Ok, enough for now... Here's a simple example using gulp:
var gulp = require("gulp");
var sass = require("gulp-sass");
var rename = require("gulp-rename");
var env = getArg("--env");
gulp.task("styles", function () {
return gulp.src("./index.scss")
.pipe(sass({
style: env === "production" ? "compressed" : "nested"
}))
.pipe(rename({
extname: env === "production" ? ".min.css" : ".css"
}))
.pipe(gulp.dest("./build"));
});
Run it gulp --env production
I built a plugin to inject parameters from the commandline into the task callback.
gulp.task('mytask', function (production) {
console.log(production); // => true
});
// gulp mytask --production
https://github.com/stoeffel/gulp-param
If someone finds a bug or has a improvement to it, I am happy to merge PRs.
And if you are using typescript (gulpfile.ts) then do this for yargs (building on #Caio Cunha's excellent answer https://stackoverflow.com/a/23038290/1019307 and other comments above):
Install
npm install --save-dev yargs
typings install dt~yargs --global --save
.ts files
Add this to the .ts files:
import { argv } from 'yargs';
...
let debug: boolean = argv.debug;
This has to be done in each .ts file individually (even the tools/tasks/project files that are imported into the gulpfile.ts/js).
Run
gulp build.dev --debug
Or under npm pass the arg through to gulp:
npm run build.dev -- --debug
Pass arguments from the command line
// npm install --save-dev gulp gulp-if gulp-uglify minimist
var gulp = require('gulp');
var gulpif = require('gulp-if');
var uglify = require('gulp-uglify');
var minimist = require('minimist');
var knownOptions = {
string: 'env',
default: { env: process.env.NODE_ENV || 'production' }
};
var options = minimist(process.argv.slice(2), knownOptions);
gulp.task('scripts', function() {
return gulp.src('**/*.js')
.pipe(gulpif(options.env === 'production', uglify())) // only minify in production
.pipe(gulp.dest('dist'));
});
Then run gulp with:
$ gulp scripts --env development
Source
var isProduction = (process.argv.indexOf("production")>-1);
CLI gulp production calls my production task and sets a flag for any conditionals.
It has been some time since this question has been posted, but maybe it will help someone.
I am using GULP CLI 2.0.1 (installed globally) and GULP 4.0.0 (installed locally) here is how you do it without any additional plugin. I think the code is quite self-explanatory.
var cp = require('child_process'),
{ src, dest, series, parallel, watch } = require('gulp');
// == availableTasks: log available tasks to console
function availableTasks(done) {
var command = 'gulp --tasks-simple';
if (process.argv.indexOf('--verbose') > -1) {
command = 'gulp --tasks';
}
cp.exec(command, function(err, stdout, stderr) {
done(console.log('Available tasks are:\n' + stdout));
});
}
availableTasks.displayName = 'tasks';
availableTasks.description = 'Log available tasks to console as plain text list.';
availableTasks.flags = {
'--verbose': 'Display tasks dependency tree instead of plain text list.'
};
exports.availableTasks = availableTasks;
And run from the console:
gulp availableTasks
Then run and see the differences:
gulp availableTasks --verbose
We wanted to pass a different config file for different environments -- one for production, dev and testing. This is the code in the gulp file:
//passing in flag to gulp to set environment
//var env = gutil.env.env;
if (typeof gutil.env.env === 'string') {
process.env.NODE_ENV = gutil.env.env;
}
This is the code in the app.js file:
if(env === 'testing'){
var Config = require('./config.testing.js');
var Api = require('./api/testing.js')(Config.web);
}
else if(env === 'dev'){
Config = require('./config.dev.js');
Api = require('./api/dev.js').Api;
}
else{
Config = require('./config.production.js');
Api = require('./api/production.js')(Config.web);
}
And then to run it gulp --env=testing