I am not too good with front-end technologies... So if I have wrong expectations - please correct me or my code. I have created a repository with code that allows to reproduce issue. Here is the link:
https://github.com/ffatheranderson/webpack-issue-reproduction
as described in readme.md of the project:
========================================
What I expect? - I expect that after I execute npm run watch command - the generated
result/bundle.js file to have such lines:
...
var _environment = 'development';
var _ANOTHER_VARIABLE = "another variable value";
...
What is actual result? - after I execute npm run watch command - the generated
result/bundle.js file contains such lines:
...
var _environment = undefined;
var _ANOTHER_VARIABLE = "another variable value";
...
Why do I have such expectations? - because of these lines:
...
plugins: [
new webpack.DefinePlugin({
ENVIRONMENT: JSON.stringify(process.env.NODE_ENV),
ANOTHER_VARIABLE: JSON.stringify("another variable value"),
})
]
...
in webpack.config.js file.
As you can see variable _environment is not initialized with development value as it is promised
here: https://webpack.js.org/configuration/mode/
========================================
_environment is undefined because the environment variable NODE_ENV is undefined. You can solve this in one of three:
Invoking npm run watch --node-env=development: https://webpack.js.org/api/cli/#node-env
Exporting NODE_ENV in your current shell session:
$ export NODE_ENV=production; npm run watch
Updating your configuration to specify the value from some other source (e. g. an --env argument, a file on disk, hard-coding it, etc.)
Related
Please correct my understanding for the below:
I've installed protractor flake
From the website we have 2 sets of
code
My assumption
I'm pretty sure the B part needs to be given in configuration.js file
of my protractor project but the A part where exactly should it be written.
As a separate file should i write it and then require them in the spec file which i'm running.I need exact steps as to achieve the above
The usage section which starts with below:
**var protractorFlake = require('protractor-flake')
// OR using es6 modules/typescript
import protractorFlake = require('protractor-flake')**
and ends with **process.exit(status)**
and the parsers section which starts with
module.exports = { till return [...failedSpecs]
As per the documentation,
Add dependency
npm i protractor-flake
# or globally for easier cli usage
npm i -g protractor-flake
Running tests
Option 1: Via the CLI:
# protractor-flake <protractor-flake-options> -- <options to be passed to protractor>
protractor-flake --parser standard --max-attempts=3 -- path/to/protractor.conf.js
Assuming that your conf.js file is in root directory.
Available command line options.
color?: string | boolean
choose color from here or set false to disable coloring
Usage : protractor-flake --parser standard --color=magenta --max-attempts=3 -- conf.js
protractorArgs?: string[]
protractorPath?: string: protractor location like this 'node_modules/.bin/protractor',
Usage : protractor-flake --parser standard --protractorPath=node_modules/.bin/protractor --max-attempts=3 -- conf.js
parser?: string: the name of one of the included parsers
Usage : protractor-flake --parser standard --color=magenta --max-attempts=3 -- conf.js
You can refer other options from here
Option 2: Programmatically
Create file in your root directory as flake and copy below snippet.
flake is a node script that uses protractor-flake to re-run failed tests. Note
that it reruns tests at the file level, so if one test fails, it will rerun all
the tests in that file.
Thanks Brian Ray to this repository
#!/usr/bin/env node
/**
*
* usage:
* `./flake conf.js [other protractor args]`
*/
const protractorFlake = require('protractor-flake');
// skip first two passed args (node and self)
let protractorArgs = process.argv.splice(2);
console.log(protractorArgs);
protractorFlake({
protractorPath: 'node_modules/.bin/protractor',
maxAttempts: 3,
parser: 'standard',
nodeBin: 'node',
protractorArgs: protractorArgs
}, (status, output) => {
process.exit(status);
});
After creating this file, for avoiding permission error's just run chmod +x ./flake
To run your test cases
./flake conf.js
If you are keeping specs in a test suite, just pass after conf.js.
./flake conf.js --suite smoke_test
Before you are running, check these Caveats
I'm trying to use an environment variable during the build stage of a CI job for a VueJS app. I'm using GitLab CI, and one of the environment variables that is made available is CI_COMMIT_SHORT_SHA,
build:
image: node:latest
stage: build
variables:
CI_COMMIT_SHORT_SHA: "$CI_COMMIT_SHORT_SHA"
artifacts:
paths:
- dist/
script:
- npm install --progress=false
- npm run build
- echo "Build Complete"
Here's how I'm trying to use this variable in Vue:
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>This is a static site that is served with a CloudFront distribution in front of an S3 bucket.</p>
<p>The site is updated through a GitLab CI/CD pipeline.</p>
<p>Commit ref: {{ commit }}</p>
<p>Using cache invalidation</p>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
},
data(){
return {
commit: process.env.CI_COMMIT_SHORT_SHA
}
}
}
</script>
I'm not seeing this variable come through. Is there something else I need to do in order to access the environment variable and display it in my component?
As mentioned in https://cli.vuejs.org/guide/mode-and-env.html#using-env-variables-in-client-side-code
Only variables that start with VUE_APP_ will be statically embedded into the client bundle with webpack.DefinePlugin. You can access them in your application code:
console.log(process.env.VUE_APP_SECRET)
If you're using webpack.config, you can set up DefinePlugin in a similar way.
In your webpack.config.js you would use a new plugin,
new webpack.DefinePlugin({
/*
JSON.stringify(yourconfig) is highly recommened
to avoid overwriting existing keysother process.env
*/
'process.env': JSON.stringify(config.prod), // or config.dev
}),
Where config.prod / config.dev is something like
let config = {};
config.prod = require('./config/prod.env'); // imports ./config/prod.env.js
config.dev = require('./config/dev.env');
at the top of the file,
and the prod.env.js and dev.env.js files look something like
'use strict';
module.exports = {
VUE_APP_MODE: 'MYMODE'
};
If you wanted to match the vue process more closely,you could filter out the object keys using RegExp /^VUE_APP_.*/.
Then in the data section of your .vue file you can include these by using:
data: {
VUE_APP_MODE: process.env.VUE_APP_MODE
}
After some research it seemed that the vue-cli-service build command only looks into the dot-files in the root of your project, and only processes these variables starting with VUE_APP_ (in various .env files)
You could set all the variables in the Gitlab CI options and then copy those variables to the .env file. Now, when vue-cli builds the project, it injects these values in the transpiled scripts.
You could issue a command like this before you build the project:
env | grep 'VUE_APP_' > .env
I also use a staging environment that is built when pushing into the staging branch. Therefore I have these variables set into Gitlab:
VUE_APP_VAR1=foo
VUE_APP_VAR2=bar
VUE_ACCEPT_VAR1=foo
VUE_ACCEPT_VAR2=bar
Since vue-cli wants the variables to start with VUE_APP_ I do a replace with sed:
env | grep 'VUE_ACCEPT_' | sed 's/VUE_ACCEPT_/VUE_APP_/' > .env
I have a requirement where we need to set dll path based upon whether it is executing in production or in development environment. So I decided to place that value in environment variable and tried to achieve that using webpack.DefinePlugin({}).
Method 1:
webpack.config.json
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV' : JSON.stringify('production')
})
And then I tried to get that value in electron's main process, In my case elec.js
elec.js
const Electron = require("electron");
const app = require("electron");
var dllPath = "";
function createWindow() {
let win = new BrowserWindow({
width: 800,
height: 600,
title: "Test",
icon: "Test.ico"
});
win.setMenu(null);
win.loadURL(
url.format({
pathname: path.join(__dirname, "../renderer/index.html"),
protocol: "file:",
slashes: true
})
);
if (process.env.NODE_ENV ==='production') {
dllPath = path.join(
__dirname,
"./../../dll/test.dll"
);
} else {
dllPath = path.join(
__dirname,
"./../../../dll/test.dll"
);
}
}
app.on("ready", createWindow);
But problem is that when I try to access that value in createWindow() function it is undefined so flow always goes to else block.
Is there anything I am missing?
Method 2:
I tried to achieve the same using cross-env node package, but no luck. Please find below code block which I tried using cross-env.
package.json
"scripts": {
"build": "cross-env process.env.NODE_ENV=production && rimraf ./dist/ && webpack --progress && node-sass
./src/renderer/scss/ -o ./dist/renderer/ && rimraf ./dist/renderer/includes/"
}
The problem is multi-faceted.
First, your elec.js is executed by Electron before the app is loaded. Electron runs elec.js, which creates the Browser window (let win = new BrowserWindow(...)) and loads HTML file (win.loadURL(...)) into it inside the browser process, the HTML then loads your webpack'ed js. So none of the webpacked js code is available in the elec.js. The webpack'ed code is also running in another process than the elec.js.
Another thing to note is that webpack plugin does not create any assignment to the variable it points too. It is done by simple text search and replace, in your example, all instances of process.env.NODE_ENV will be replaced with "production" string in the source code that is webpack'ed. That is not too obvious, but messes up the expected results.
One last thing - webpack plugin does not change any code in elec.js file, as that file is not webpack'ed.
So all that makes process.env.NODE_ENV from the build/webpack time not available in the elec.js code.
Once the mechanisms are clear, there are few ways to solve the problem, I will give general ideas, as there are plenty of discussions on each, and depending on circumstances and desired use case, some are better than others:
Generate a js file with necessary assignments based on environment variable during build (e.g. copy one of env-prod.js / env-dev.js -> env.js), copy it next to the elec.js, and reference it (require(env.js)) in elec.js.
Pass environment variable from command line (e.g. NODE_ENV=1 electron .) - it will get to elec.js.
Include a file into webpack based on environment variable (e.g. copy one of env-prod.js / env-dev.js -> env.js) and peek into webpacked' files from elec.js, e.g. using asar commands.
Use different version in package.json depending on build (e.g. version: "1.0.0-DEBUG" for debug), and read & parse it by calling app.getVersion() in elec.js. It is tricky as package.json should be a single file, but OS commands could be used (e.g. in "scripts") to copy one of prepared package.json files before invoking npm.
Here are some links that could help too:
Electron issue #7714 - discussion on relevant features in Electron
electron-is-dev - module checking if it is in dev
Electron boilerplate - example boilerplate that uses config/env-prod/dev files
The insight provided by iva2k is what allowed me to come to a solution for this same problem.
Using dotenv to create a .env file for my config got me halfway to where I wanted to be (setting up a few environment variables for use in a production setting). The problem then became that Electron wasn't passing those from the Main process down to the Renderer process by default.
The work-around is simple: use Electron's own ipcMain and ipcRenderer modules to pass the dotenv object between the two.
In your main file (e.g. your elec.js file), place an ipcMain event listener after requiring the module:
const config = require('dotenv').config();
const electron = require('electron');
const { app, BrowserWindow, ipcMain } = electron;
...
ipcMain.on('get-env', (event) => {
event.sender.send('get-env-reply', config);
});
Elsewhere, in your application's rendering-side, place this anywhere necessary:
async function getConfig()
{
const { ipcRenderer } = window.require('electron');
let config = null;
ipcRenderer.on('get-env-reply', (event, arg) => {
// The dotenv config object should return an object with
// another object inside caled "parsed". Change this if need be.
config = arg.parsed;
});
ipcRenderer.send('get-env');
return config;
}
This basically allowed me to declare one event in the Main process file, and then re-use it in any process-side file I wanted, thus allowing me to obfuscate config variables in a file that goes with the build, but isn't accessible to end-users without opening up the dev-tools.
Maybe late but can use simple hack in elec.js
const isProduction = process.env.NODE_ENV === 'production' || (!process || !process.env || !process.env.NODE_ENV);
In your console
For Windows
set MY_VARIABLE=true
For linux
$ export MY_VARIABLE=true
window.process.env.MY_VARIABLE
The template is based on vuejs-webpack, and the build, config files are here, I have not modified any of these files.
Based on Environment Variables the keys defined in dev.env.js file must be accessible when running npm run dev in the app.
This is the content of my dev.env.js:
'use strict'
const merge = require('webpack-merge')
const prodEnv = require('./prod.env')
module.exports = merge(prodEnv, {
NODE_ENV: '"development"',
SAMPLE: '"XX"',
AUTH_URL: '"http://localhost:3030"'
})
And when I try to access AUTH_URL in App.vue like this process.env.AUTH_URL, I receive undefined.
It seems to me whatever is defined in dev.env.js file will never become accessible when running npm run dev
Use the webpack.DefinePlugin to define the variables you wish to share with your front end. Webpack its self does not expose process to the browser as this is a node js function.
const dev_env = require('dev.env.js)
plugins: [
new webpack.DefinePlugin({
'process.env' : {
NODE_ENV: JSON.stringify(dev_env.NODE_ENV)
}
})
]
Some variation of the above should work for you.
If your run "npm run dev", then your new environment variable is only available after a restart of npm (Ctrl + C and again 'npm run dev').
I've got an Angular2 project with this structure :
client/ // Angular2 client
app/
app.component.ts
...
main.ts
...
server/ // API
server.js
config/ // config files
webpack.config.js
...
I'd like to have all constants and parameters of the Angular2 app (like the url to the API...) in the config directory, with all other config files.
How can I perform it in Angular2 ? As the config folder is outside the client folder, is it a good practice to import something that is outside, with many "../../../" ?
Also I wanted to use dependency injection, but is there anything less heavy ?
And how can I avoid to import manually the file in each component/module I want to use it ?
Thx
What I used is probably the not best approach but, I'm using webpack to inject global variables with the DefinePlugin plugin:
I use the .env file on root, to store the variables, I have a .env.TST, .env.PRD and replace it with deployment script
webpack.common.js
var preEnv = require('../.env');
var envVars = {};
for(var propertyName in preEnv) {
envVars[propertyName] = '"'+preEnv[propertyName]+'"';
}
...
plugins: [
new webpack.DefinePlugin(
envVars
)
]
...
Example .env file
module.exports = {
"APIURL": "https://localhost/MyAPI/",
"PUBLIC_URL": "https://localhost:3000/",
"BASE_PATH": "/"
"ENV": "dev"
}
And you will have APIURL as a global variable
Additionaly I added a file into the typings, to prevent warnings:
typings/typings.d.ts
declare var APIURL: string;
declare var PUBLIC_URL: string;
declare var ENV: string;
declare var BASE_PATH: string;
I hope it helps to someone
Inside you package.json you can write an npm script for every environment. that you are going to support:
"scripts": {
"build:dev": "webpack --config config/webpack.dev.js",
"build:prod": "webpack --config config/webpack.prod.js"
}
Then in every config/webpack.xxxx.dev script you can declare global variables using Webpack DefinePlugin || ExtendedDefinePlugin. It is vital to understand that this plugin allows you to have your global server-side node.js variables, become available as global client-side .js variables.
This is how your webpack.dev.js might look like
new DefinePlugin({
'ENV': JSON.stringify('Development'),
'URL': JSON.stringify('http://...')
})
...
This is how your webpack.prod.js might look like
new DefinePlugin({
'ENV': JSON.stringify('Prod'),
'URL': JSON.stringify('http://...')
})
...
Finally is your .ts files you can then write
declare var URL: string; //keeps the compiler happy
let configUrl: string = URL;
link to example github project: ng2a.frontend