process.env is always empty event though i am using webpack.defineplugin - node.js

I have tried with adding webpack.defineplugin in my code and I am not able to get data from process.env object i.e object is empty then next I try with adding node:{process:false} in module.export but my project is not able to render app.js file
When I run the npm script and start the local browser I am not able to figure out why process.env is empty all the time
Then I try with adding node:{process:false} so that we can touch global process.env by using webpack.defineplugin but then i am not able to see my react.dom element or Login page , my react code in not getting executed
webpack.config.js file
module.exports = (env) => {
// Get the root path (assuming your webpack config is in the root of your project!)
const currentPath = path.join(__dirname);
console.log(__dirname);
// Create the fallback path (the production .env)
const basePath = currentPath + '/.env';
// We're concatenating the environment name to our filename to specify the correct env file!
const envPath = basePath + '.' + env.ENVIRONMENT;
// Check if the file exists, otherwise fall back to the production .env
const finalPath = fs.existsSync(envPath) ? envPath : basePath;
console.log("final path" + finalPath);
// Set the path parameter in the dotenv config
const fileEnv = dotenv.config({ path: finalPath }).parsed;
const envKeys = Object.keys(fileEnv).reduce((prev, next) => {
prev[`process.env.${next}`] = JSON.stringify(fileEnv[next]);
return prev;
}, {});
console.log("env keys ", envKeys);
return {
node: {
process: true
},
entry: [
// POLYFILL: Set up an ES6-ish environment
// 'babel-polyfill', // The entire babel-polyfill
// Or pick es6 features needed (included into babel-polyfill)
'core-js/fn/promise',
'core-js/es6/object',
'core-js/es6/array',
'./src/index.jsx', // your app's entry point
],
devtool: process.env.WEBPACK_DEVTOOL || 'eval-source-map',
output: {
path: path.join(__dirname, 'public'),
filename: "bundle.js",
publicPath: '/'
},
module: {
rules: loadersConf
},
resolve: {
extensions: ['.js', '.jsx'],
modules: [
path.join(__dirname, "src"),
path.join(__dirname, "node_modules"), // the old 'fallback' option (needed for npm link-ed packages)
],
alias: {
"styles": path.resolve(__dirname, 'styles/'),
}
},
devServer: {
contentBase: "./public",
// do not print bundle build stats
noInfo: true,
// enable HMR
hot: true,
// embed the webpack-dev-server runtime into the bundle
inline: true,
// serve index.html in place of 404 responses to allow HTML5 history
historyApiFallback: true,
port: PORT,
host: HOST,
},
plugins: [
new webpack.DefinePlugin(envKeys),
new webpack.NoEmitOnErrorsPlugin(),
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin(),
new ExtractTextPlugin({
filename: 'style.css',
allChunks: true
}),
new DashboardPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html',
files: {
css: ['style.css'],
js: ["bundle.js"],
}
}),
]
}
};

Related

How do I integrate NewRelic into a Node Typescript Express server bundled with Webpack?

Frankly, I've tried it all. I'm not a total whiz with Webpack, however I seem to be getting along pretty well over the years with configuring new projects.
What I cannot seem to do now is set up the NewRelic service into an existing Node/Typescript/Express/Webpack application.
As it stands, my app gets nicely bundled to a single file in my /dist folder and runs quick and nimble. Seems like this 'node agent' put out by New Relic doesn't play well with Typescript imports.
Webpack Config
const path = require('path');
const webpack = require('webpack');
const nodeExternals = require('webpack-node-externals');
const NodemonPlugin = require ('nodemon-webpack-plugin');
module.exports = (env = {}) => {
const config = {
entry: ['./src/app.ts'],
mode: env.development ? 'development' : 'production',
target: 'node',
devtool: env.development ? 'inline-source-map' : false,
resolve: {
extensions: ['.ts', '.js'],
modules: ['node_modules', 'src', 'package.json'],
},
module: {
rules: [
{
test: /\.ts$/,
use: ['ts-loader', 'eslint-loader'],
// exclude: /node_modules/,
},
],
},
plugins: [],
externals: [ 'newrelic', nodeExternals() ]
};
if (env.nodemon) {
config.watch = true;
config.plugins.push(new NodemonPlugin())
}
return config;
};
there exists a standard /project_root/.newrelic file
CircleCi picks up this project up and runs "build:ci" script from package.json ==> "webpack"
output is /dist/main.js
references
https://docs.newrelic.com/docs/agents/nodejs-agent/installation-configuration/install-nodejs-agent
https://docs.newrelic.com/docs/agents/nodejs-agent/installation-configuration/nodejs-agent-configuration
https://discuss.newrelic.com/t/node-agent-fails-with-webpack/24874
Your first line of the starting point of the app should be
import newrelic from 'newrelic';
Of course, run npm install newrelic --save first
Then, create a newrelic.js file on the root of the repo (outside of src).
Then you put in the details like:
'use strict'
exports.config = {
app_name: ['appName'],
license_key: '1234567890',
allow_all_headers: true,
attributes: {
exclude: [
'request.headers.cookie',
'request.headers.authorization',
'request.headers.proxyAuthorization',
'request.headers.setCookie*',
'request.headers.x*',
'response.headers.cookie',
'response.headers.authorization',
'response.headers.proxyAuthorization',
'response.headers.setCookie*',
'response.headers.x*'
]
}
}

Webpack not creating the HTML file it used to create

I was building a nodejs app (typescript, react, webpack) and the build was working fine. I.e. I got in the output what I expected. A HTML file, with the bundle file I expected.
Suddenly, without any change in my code, webpack is only generating a the bundle javascript file (as usual) but the HTML file is gone, i.e it does not generate any more.
Here my webpack config file:
const path = require('path');
const config = {
mode: "production",
entry: path.resolve(__dirname, "../src/index.tsx"),
resolve: {
extensions: ['.tsx', '.js']
},
output: {
// options related to how webpack emits results
path: path.resolve(__dirname, "../dist"),
filename: "bundle.js"
},
module: {
rules: [
{
test: /.tsx$|.js$/,
loader: "ts-loader" ,
include: path.resolve(__dirname, "../src")
},
]
}
}
module.exports = config;
Any clue why my HTML file is not generated anymore and how I can recover it? Thank you!
As I know Webpack by default outputs main.js if you do not specify output filename configuration like this code. Try this code:
const path = require('path');
const config = {
entry: path.resolve(__dirname, "../src/index.tsx"),
resolve: {
extensions: ['.tsx', '.js']
},
output: {
// options related to how webpack emits results
path: path.resolve(__dirname, "../dist"),
filename: 'my-first-webpack.bundle.js'
},
module: {
rules: [
{
test: /\.tsx$/,
loader: "ts-loader" ,
include: path.resolve(__dirname, "../src")
},
]
}
}
module.exports = config;
So the HTML was actually never created. So the question is obsolete.
I was confused because before there used to be an HTML in the output. But it was not generated by webpack (it came from Typescript script)

Accessing process.env.PORT defined in Elastic Beanstalk Node, bundle built by Webpack

Currently I'm building out a REACT app on my local machine and deploying it's production build to Elastic Beanstalk. It is built using Webpack.
In index.js (server side) I use env variables such as: process.env.PORT (Defined in Elastic Beanstalk), when Webpack builds it out, these are replaced with Objects({}) containing local process.env.
Is there a way to prevent Webpack from evaluating certain env variables?
or am I going about it wrong and do I need to build the production bundle on Elastic Beanstalk first and then serve?
Worst case I can simply add the required values to a dotenv file and approach it that way. I would prefer to be able to make use of Elastic Beanstalks Enviroment Variables though.
Thanks in advance
Update:
To better explain below, I'm trying to access process.env variables during runtime in the server side script. The code is however built on my local machine before being deployed to AWS Elastic Beanstalk
webpack.config.server
'use strict';
const util = require('util');
const path = require('path');
const webpack = require('webpack');
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
// const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
const paths = require('./paths');
const nodeExternals = require('webpack-node-externals');
const getClientEnvironment = require('./env');
const merge = require('webpack-merge');
const base = require('./webpack.config.base');
const publicUrl = '';
// Get environment variables to inject into our app.
const env = getClientEnvironment(publicUrl);
const config = {
target: 'node',
entry: paths.serverIndexJs,
externals: [nodeExternals()], // / in order to ignore all modules in node_modules folder
output: {
path: paths.serverBuild,
filename: 'bundle.js',
publicPath: '/'
},
module: {
rules: [
// "postcss" loader applies autoprefixer to our CSS.
// "css" loader resolves paths in CSS and adds assets as dependencies.
// "style" loader turns CSS into JS modules that inject <style> tags.
// In production, we use a plugin to extract that CSS to a file, but
// in development "style" loader enables hot editing of CSS.
{
test: /\.scss$/,
include: [ path.resolve(paths.scss, 'vendor') ], // Global styles
use: [
{
loader: "isomorphic-style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader", // translates CSS into CommonJS
options: {
importLoaders: 1,
sourceMap: true
}
}, {
loader: "postcss-loader",
options: {
sourceMap: true
}
}, {
loader: "sass-loader", // compiles Sass to CSS
options: {
sourceMap: true
}
}
]
},
{
test: /\.scss$/,
exclude: [ path.resolve(paths.scss, 'vendor'), path.resolve(__dirname, '../node_modules') ], // Module styles
use: [
{
loader: "isomorphic-style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader", // translates CSS into CommonJS
options: {
importLoaders: 1,
sourceMap: true,
modules: true,
localIdentName: '[path]___[name]__[local]___[hash:base64:5]'
}
}, {
loader: "postcss-loader",
options: {
sourceMap: true
}
}, {
loader: "sass-loader", // compiles Sass to CSS
options: {
sourceMap: true
}
}, {
loader: "sass-resources-loader",
options: {
resources: [
path.resolve(__dirname, '../node_modules/bootstrap/scss/_functions.scss'),
path.resolve(__dirname, '../src/scss/config/**/*.scss'),
path.resolve(__dirname, '../node_modules/bootstrap/scss/mixins/**/*.scss'),
path.resolve(__dirname, '../src/scss/helpers/**/*.scss'),
]
}
}
]
},
]
},
plugins: [
// Makes some environment variables available to the JS code, for example:
// if (process.env.NODE_ENV === 'development') { ... }. See `./env.js`.
new webpack.DefinePlugin(env.stringified),
],
node: {
console: false,
global: false,
process: false,
Buffer: false,
__filename: false,
__dirname: false,
setImmediate: false,
}
};
module.exports = merge(base, config);
Not 100% clear on what you're trying to do, but it sounds like you want to pass only some of the environment vars to the DefinePlugin, not all of them...? If that's the case you can just write a little fn to filter or whitelist the env vars and pass the result to DefinePlugin. If an env var isn't included in your DefinePlugin, webpack will be unaware of it at build time.
getClientEnvironment from env.js returned an object of key values which was then passed to DefinePlugin.
Although environment variables such as process.env.PORT weren't being passed to DefinePlugin they were being complied by Webpack as undefined.
This was due to getClientEnviroment returning the environment variables as an object of process.env
{ 'process.env':
{ NODE_ENV: '"production"',
PUBLIC_URL: '""',
REACT_APP_HOST: '"localhost"',
REACT_APP_PORT: '"8080"'
}
}
What I didn't realise was that in doing this, DefinePlugin overrides all process.env variables.
As per definePlugin's docs:
When defining values for process prefer 'process.env.NODE_ENV':
JSON.stringify('production') over process: { env: { NODE_ENV:
JSON.stringify('production') } }. Using the latter will overwrite the
process object which can break compatibility with some modules that
expect other values on the process object to be defined.

How to structure a Vue 2.0 app for server-rendered lazy routes?

I attempted to modify vue-hackernews-2.0 to support lazy-loaded routes using Webpack's code-splitting feature as per instructions found at these links:
https://router.vuejs.org/en/advanced/lazy-loading.html
http://vuejs.org/guide/components.html#Async-Components
However, I ran into some issues. When I loaded the app in the browser, all suggested variations of syntax triggered Module not found errors on the server-side when attempting to load in the server-side chunks.
Given this wrapper around the code-split points in router.js...
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
// INSERT CODE-SPLIT POINT SYNTAXES HERE (they are below)
export default new Router({
mode: 'history',
routes: [{
path: '/',
component: Home
}, {
path: '/foo',
component: Foo
}]
})
All of these variations of syntax threw the Module not found error:
Variation 1:
const Home = () => System.import('./views/Home.vue')
const Foo = () => System.import('./views/Foo.vue')
Variation 2:
const Home = (resolve) => require(['./views/Home.vue'], resolve)
const Foo = (resolve) => require(['./views/Foo.vue'], resolve)
Variation 3:
const Home = (resolve) => {
require.ensure(['./views/Home.vue'], () => {
resolve(require('./views/Home.vue'))
})
}
const Foo = (resolve) => {
require.ensure(['./views/Foo.vue'], () => {
resolve(require('./views/Foo.vue'))
})
}
The error message was always along the lines of:
(note: this error is adapted from a small reproduction I made of the issue, not from the hackernews example)
Error: Cannot find module './0.server.js'
at Function.Module._resolveFilename (module.js:440:15)
at Function.Module._load (module.js:388:25)
at Module.require (module.js:468:17)
at require (internal/module.js:20:19)
at Function.requireEnsure [as e] (__vue_ssr_bundle__:42:25)
at Home (__vue_ssr_bundle__:152:30)
at /Users/razorbeard/projects/vue-2-ssr/node_modules/vue-router/dist/vue-router.js:1421:19
at iterator (/Users/razorbeard/projects/vue-2-ssr/node_modules/vue-router/dist/vue-router.js:1277:5)
at step (/Users/razorbeard/projects/vue-2-ssr/node_modules/vue-router/dist/vue-router.js:1213:9)
at step (/Users/razorbeard/projects/vue-2-ssr/node_modules/vue-router/dist/vue-router.js:1217:9)
I tried adapting my code to use the suggestions offered at Server-side react with webpack 2 System.import, but those did not work either.
I read a post that described configuring a build-time global variable using Webpack's DefinePlugin that allowed me to inspect whether the code was running on the server or on the client - this allows me to code-split on the client, but just bundle everything in on the server.
In the server webpack config:
{
...
plugins: [
new webpack.DefinePlugin({
BROWSER_BUILD: false
})
]
...
}
In the client webpack config:
{
...
plugins: [
new webpack.DefinePlugin({
BROWSER_BUILD: true
})
]
...
}
Then, in the same wrapper-snippet as above for the router.js file, I used this variation of syntax:
const Home = BROWSER_BUILD ? () => System.import('./views/Home.vue') : require('./views/Home.vue')
const Foo = BROWSER_BUILD ? () => System.import('./views/Foo.vue') : require('./views/Foo.vue')
This made rendering work - partially. Navigating directly to the app in the browser (and respective routes) server-rendered the correct UI. Clicking around, vue-router's client-side logic took me to the right UI. Everything seemed hunky-dory - until I opened DevTools:
The same issue also occurs if a module is loaded lazily as a subcomponent of a route:
<template>
<div class="page">
<heading></heading>
</div>
</template>
<script>
const Heading = BROWSER_BUILD ? () => System.import('./Heading.vue') : require('./Heading.vue')
export default {
components: {
Heading
}
}
</script>
I tried asking for some help in the official Vue forum, but came up empty: http://forum.vuejs.org/t/2-0-help-needed-with-server-rendered-lazy-routes/906
Thinking this might be a bug with vue-router, I opened an issue there: https://github.com/vuejs/vue-router/issues/820
Unfortunately, I wasn't able to find a solution.
So, I put together a small repo that reproduces the issue: https://github.com/declandewet/vue2-ssr-lazy-error
I have a hunch that the actual problem might be coming from https://www.npmjs.com/package/vue-server-renderer.
I'm really stuck on this and am used to how easy it is to do in react - and would really appreciate any help/tips/direction towards a solution!
Here is the webpack config from the reproduction repo for convenience:
import fs from 'fs'
import path from 'path'
import webpack from 'webpack'
import validate from 'webpack2-validator'
import { dependencies } from './package.json'
let babelConfig = JSON.parse(fs.readFileSync('./.babelrc'))
/* turn off modules in es2015 preset to enable tree-shaking
(this is on in babelrc because setting it otherwise causes issues with
this config file) */
babelConfig.presets = babelConfig.presets.map(
(preset) => preset === 'es2015' ? ['es2015', { modules: false }] : preset
)
const babelOpts = {
...babelConfig,
babelrc: false,
cacheDirectory: 'babel_cache'
}
const SHARED_CONFIG = {
devtool: 'source-map',
module: {
loaders: [{
test: /\.vue$/,
loader: 'vue'
}, {
test: /\.js$/,
loader: 'babel',
exclude: 'node_modules',
query: babelOpts
}]
},
resolve: {
modules: [
path.join(__dirname, './src'),
'node_modules'
]
}
}
const SERVER_CONFIG = validate({
...SHARED_CONFIG,
target: 'node',
entry: {
server: './src/server.js',
renderer: './src/renderer.js'
},
output: {
path: path.join(__dirname, './dist'),
filename: '[name].js',
chunkFilename: '[id].server.js',
libraryTarget: 'commonjs2'
},
plugins: [
new webpack.DefinePlugin({
BROWSER_BUILD: false,
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
}),
new webpack.BannerPlugin({
banner: 'require("source-map-support").install();',
raw: true,
entryOnly: false
})
],
externals: Object.keys(dependencies)
})
const CLIENT_CONFIG = validate({
...SHARED_CONFIG,
entry: {
app: './src/client.js',
vendor: ['vue']
},
output: {
path: path.join(__dirname, './dist/assets'),
publicPath: '/',
filename: 'bundle.js'
},
plugins: [
new webpack.DefinePlugin({
BROWSER_BUILD: true,
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: 'vendor.js'
})
]
})
export default [SERVER_CONFIG, CLIENT_CONFIG]
EDIT: Noticing that in React, we use match on the client to get the right route config for the current view, I decided to inspect what components were getting matched using app.$router.getMatchedComponents() and found something interesting:
Server Entry:
import app from './app'
export default (context) => {
// using app.$router instead of importing router itself works
// (not sure why the hacker-news example imports the router module instead...)
app.$router.push(context.url)
const components = app.$router.getMatchedComponents()
console.log('server-side', components)
return Promise.all(components.map((component) => component))
.then(() => app)
}
When navigating to the home page, this logs to the terminal:
server-side [ { __file: '/Users/razorbeard/projects/vue-2-ssr/src/views/Home.vue',
render: [Function],
staticRenderFns: [ [Function] ] } ]
Client Entry:
import app from './app'
const components = app.$router.getMatchedComponents()
console.log('client-side', components)
// kickoff client-side hydration
Promise.all(components.map((component) => Promise.resolve(component)))
.then(() => app.$mount('#app'))
When navigating to the home page, this logs to the devtools console:
client-side []
As you can see, no components are getting matched on the client side.

Cannot get HotModuleReplace plugin with react-hot to be enabled in the browser, though file watching is working

I'm trying to use webpack's Hot Module Replacement plugin. I've managed to randomly get it working, but it still isn't doing quite what I would hope it to.
Basically, I get no messages in my console that it's even active, though it's building without issue and file watching is working, as I get the messages webpack: bundle is now VALID and webpack: bundle is now INVALID when I update.
webpack, webpack-dev-server, and react-hot are all installed locally.
But in the browser's console, the only thing I see is:
Download the React DevTools for a better development experience: https://fb.me/react-devtools
I'm using Laravel to update my index file based on an environment variable and it is working just fine.
Here is the index.php file:
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div id="content"></div>
#if(env("APP_HOTRELOAD"))
<script src="http://localhost:8080/js/vendor.js"></script>
<script src="http://localhost:8080/js/app.js"></script>
#else
<script src="js/vendor.js"></script>
<script src="js/app.js"></script>
#endif
</body>
</html>
Here is the webpack config file (webpack.hot-reload.config.js):
var path = require("path");
var webpack = require("webpack");
var node_modules = path.resolve(__dirname, "node_modules");
var public_dir = path.resolve(__dirname, "public");
module.exports = {
debug: (process.env.NODE_ENV === "production"),
entry: {
vendor: [
"es5-shim",
"es5-shim/es5-sham",
"babel-core/polyfill",
"babel-core/external-helpers",
"react",
"react-router-component"
],
app: [
"webpack-dev-server/client?http://localhost:8080",
"webpack/hot/only-dev-server",
path.resolve(__dirname, "resources/assets/js/index.js")
]
},
contentBase: public_dir,
output: {
path: path.resolve(public_dir, "js"),
filename: "app.js",
publicPath: "/"
},
plugins: [
new webpack.optimize.CommonsChunkPlugin("vendor", "vendor.js"),
//This is necessary for React to know whether it's supposed to strip out
//addons and extra stuff when being minified. Essentially, it becomes dead
//code and webpack will take it out.
new webpack.DefinePlugin({
"process.env": {"NODE_ENV": JSON.stringify(process.env.NODE_ENV)}
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
],
module: {
loaders: [
{
test: /\.(sa|c)ss$/,
loader: "css!style!sass"
},
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loaders: [
"react-hot",
"strip-loader?strip[]=debug,strip[]=console.log,strip[]=console.error",
"babel-loader"
]
}
]
},
resolve: {
root: path.resolve(__dirname, "resources/assets/js"),
extensions: ["", ".js", ".json"]
}
};
In order to start the webpack-dev-server, I use a separate server.js file, executed by using node server.js:
var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var config = require('./webpack.hot-reload.config');
new WebpackDevServer(webpack(config), {
publicPath: config.output.publicPath,
contentBase: config.contentBase,
hot: true,
historyApiFallback: true,
quiet: false,
noInfo: false,
stats: {
colors: true
}
}).listen(8080, 'localhost', function (err, result) {
if (err) {
console.log(err);
}
console.log('Listening at localhost:8080');
});
It seems to work randomly after waiting some time, but if I change a file or refresh the page manually, it seems to just break. I've tried using both Firefox and Chrome and it doesn't make a difference, so I'm thinking it's in the build.
What could be wrong?
I figured it out. There was a comment about it on the page that notes how to use webpack-dev-server, but I managed to read over it.
If you look in my config you'll see:
...
output: {
path: path.resolve(public_dir, "js"),
filename: "app.js",
**publicPath: "/"**
},
...
I misinterpreted the publicPath key and its path.
However, the example given in the docs shows:
module.exports = {
entry: {
app: ["./app/main.js"]
},
output: {
path: "./build",
publicPath: "/assets/",
filename: "bundle.js"
}
};
And states:
This modified bundle is served from memory at the relative path specified in publicPath (see API). It will not be written to your configured output directory. Where a bundle already exists at the same url path the bundle in memory will take precedence.
However, for this example, this bundle will be served from /, not /assets/ because further down, the content base is given as build/. There's nothing that notes that the directory where the scripts lie is possibly aliased to /assets/ at all, so that's why I placed the / path as the publicPath instead of the subdirectory my JS was actually being served from..
The docs note that:
To teach webpack to make requests (for chunk loading or HMR) to the webpack-dev-server you need to provide a full URL in the output.publicPath option.
So I changed:
publicPath: "/"
to:
publicPath: "http://localhost:8080/js/"
And now my files are being served up correctly. I added the /js/ because that's where I my JavaScript is served from on the actual server.

Resources