Webpack not creating the HTML file it used to create - node.js

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)

Related

How can I debug this Webpack error - ERROR in bundle.js from Terser

I am trying to use webpack to bundle up a Node JS project, for the benefits it offers in terms of minimising the size of the code etc. and bundling together all of the dependencies.
My webpack job is failing with the following error:
ERROR in bundle.js from Terser
Invalid function parameter [bundle.js:186393,23]
This is my webpack.config file:
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
target: "node",
mode: "production",
entry: {
app: ["./src/vitaq_client.js"]
},
// https://webpack.js.org/configuration/node/
// node: {
// global: false,
// __filename: true,
// __dirname: true,
// },
module: {
// https://github.com/ivan-aksamentov/reactlandia-bolerplate-lite/issues/5#issuecomment-413306341
exprContextCritical: false,
rules: [
{
test: /\.node$/,
use: 'node-loader'
},
{
test: /coffee/,
use: 'node-loader'
},
{
test: /\.coffee$/,
use: [ 'coffee-loader' ]
},
// {
// test: /\.map$/,
// use: ["source-map-loader"],
// enforce: "pre"
// },
]
},
plugins: [
new CleanWebpackPlugin(),
],
output: {
path: path.resolve(__dirname, "./build"),
filename: "bundle.js"
},
};
and this is the command I am using to run it:
webpack --config webpack.config.js
From the searching I have done it seems that there is a Terser plugin for code minification, but as you can see from my config file I am not loading that plugin, so does webpack use that plugin by default? If not how could I be getting an error from Terser ?
If I set the mode to "development" in the config file, then I do not get the problem, but I suspect that is because development code would not get minified.
I am a bit stuck as to how I set about debugging this problem - are there ways of getting more output from Webpack. I have tried using the --json > compilation-stats.json command line argument when I invoke webpack, but I get a huge output file (43Mb) and I can't find anything in all of that to help.
Any suggestions would be gratefully received.
This is an error with assignment where you have an invalid function parameter at the given line of bundle.js.
You can solve this by not minimizing the webpack build:
optimization: {
minimize: false
}
Then finding the assignment error line from the error output, in the non minified bundle.
Invalid function parameter [bundle.js:186393,23]
Hope this helps someone else.

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 - How do you require an optional dependency in bundle (saslprep)

I am using webpack to bundle a number of back-end scripts into a single file during my deployment process.
When connecting to the MongoDB database there is an optional dependency, which throws a warning if it is not included.
Warning: no saslprep library specified. Passwords will not be sanitized
In my development environment this error is easily resolved by installing the optional dependency.
npm install saslprep --save
However when bundling with webpack the optional dependency is not included and the warning persists in the production deployment. I can trace the cause of this easily enough, the mongodb library is requiring this as an optional dependency:
let saslprep;
try {
saslprep = require('saslprep');
} catch (e) {
// don't do anything;
}
I have tried following the webpack documentation using shimming, externals, plugins and frankly am quite lost as to the correct approach to resolve this issue. Here is my current webpack.config file (attempting to require this as a plugin).
const path = require('path');
const webpack = require('webpack');
module.exports = {
entry: './src/api/index.ts',
target: 'node',
mode: 'production',
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'ts-loader',
exclude: /node_modules/
}
]
},
resolve: {
extensions: ['.js', '.tsx', '.ts', '.json']
},
output: {
filename: 'api.js',
path: path.resolve(__dirname, 'dist'),
},
plugins: [
new webpack.IgnorePlugin(/fsevents/),
new webpack.IgnorePlugin(/blessed/),
new webpack.ProvidePlugin({
saslprep: path.resolve(__dirname, "node_modules/saslprep/index.js")
})
],
};
Thanks in advance.
Thanks to Brendan for steering me in the right direction. Ultimately the answer was found here: http://www.matthiassommer.it/software-architecture/webpack-node-modules/
The key piece of information being:
Webpack’s compiler converts the require() call to its own webpack_require(). At runtime it looks into its internal module registry.
Following the steps outlined therein the resolution becomes:
const path = require('path');
const webpack = require('webpack');
module.exports = {
entry: './src/api/index.ts',
target: 'node',
mode: 'production',
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'ts-loader',
exclude: /node_modules/
}
]
},
resolve: {
extensions: ['.js', '.tsx', '.ts', '.json'],
},
output: {
filename: 'api.js',
path: path.resolve(__dirname, 'dist'),
},
plugins: [
new webpack.IgnorePlugin(/fsevents/),
new webpack.IgnorePlugin(/blessed/),
],
externals: {
"saslprep": "require('saslprep')"
}
};
Please note that in my testing the quotes around "saslprep" do appear to berequired when importing externals.
The module saslprep is included into the bundle but it will fail to load because it's trying to read the file code-points.mem that doesn't exist.
You have to copy this file from the saslprep package into the root of your project (the relative path must be ../code-points.mem).
It doesn't matter if you copy it by hand or with the copy-webpack-plugin plugin.
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: require.resolve("saslprep/code-points.mem"),
to: "../code-points.mem"
}
]
})
],
}
webpack should be 'seeing' that require('saslprep') code and bundling saslprep. You can confirm this by looking at the file(s) created by webpack and searching for something distinctive from the library's source code. I would look at the MongoDB code that is checking for that dependency -- it may be that the way they're checking that it exists doesn't work with the way that webpack bundles and defines the dependency. (Most authors of node libraries are probably not thinking about how the code will operate when bundled -- webpack can be used for Node, but it rarely is.) If that's the case, you might be able to reverse-engineer what the code is checking for and put it in place via an alias, etc.
I you use the webpack-node-externals package, you can also do this:
const nodeExternals = require("webpack-node-externals")
...
const webpackConfig = {
...
externals: [nodeExternals({
allowlist: ['saslprep']
})],
...
}

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.

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