webpack/terser: How can I exclude a package from minification, but still include that package in the packed result? - javascript

I've found a number of solutions for excluding particular modules from minification, but all of the solutions I've seen so far not only skip minification of those packages, they cause those packages to be completely omitted from webpack's output, requiring you to provide the omitted code by some other means.
What I want to do is continue to package all needed code into one single output file, but simply have sections of that output non-minified. Is that possible?
The reason that I want to do this in this particular case is that the mysql package is failing after minification. For the moment I've disabled all minification, but I'd rather not solve this problem that way.
const webpack = require('webpack');
const LicensePlugin = require('webpack-license-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const path = require('path');
const mode = process.env.NODE_ENV || 'production';
// noinspection JSUnresolvedFunction
module.exports = {
mode,
entry: './app/app.ts',
target: 'node',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'app.js'
},
node: {
__dirname: false,
__filename: false,
global: true
},
resolve: {
extensions: ['.ts', '.js'],
mainFields: ['fesm2015', 'module', 'main']
},
module: {
rules: [
{
test: /\.ts$/,
use: [
'ts-loader',
]
}
]
},
optimization: {
// TODO: Minification breaks mysql. How to exclude mysql from minification, but include in output?
minimize: false, // mode === 'production',
minimizer: [new TerserPlugin({
exclude: /node_modules\/mysql/, // <-- This doesn't work
terserOptions: {
output: { max_line_len: 511 },
}
})],
},
devtool: 'source-map',
ignoreWarnings: [{ message: /require function is used in a way|the request of a dependency is an expression/ }],
plugins: [
new webpack.BannerPlugin({ banner: '#!/usr/bin/env node', raw: true }),
new LicensePlugin({
outputFilename: '3rdpartylicenses.txt',
excludedPackageTest: name => /^(asynclist|emitter)/.test(name)
})
]
};
Update: The particular issue with mysql and minification seems to be mangling of variable and/or function names. If I set the mangle option to false, I can minify all of the code, including mysql, successfully. I have yet to figure out which specific names can't be mangled without causing problems.

Related

Webpack-dev-server HMR not working with multiple entry points

today I've noticed a strange bug (or I am to dumb?) with my webpack-dev-server.
I've got a Spring Boot App with thymleaf templates. Some pages may only load one others may have more than one js-file:
// main.js
import "../style.scss";
single.html:
<body>
<script th:src="#{/myapp/js/main.js}"></script>
</body>
multiple.html
<body>
<script th:src="#{/myapp/js/main.js}"></script>
<script th:src="#{/myapp/js/other.js}"></script>
</body>
I've splitted my config into a dev, production and common part:
webpack.common.js:
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: {
main: path.resolve(__dirname + "/src/main/js/main.js"),
other: path.resolve(__dirname + "/src/main/js/other.js"),
},
output: {
path: path.resolve(__dirname, "./src/main/resources/static/myapp"),
filename: "js/[name].js",
},
module: {
rules: [
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"postcss-loader",
"sass-loader",
],
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: [
// prettier-ignore
["#babel/preset-env", {
corejs: "3.6.4",
// debug: true,
useBuiltIns: "usage"
}
],
],
},
},
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: "css/[name].css",
chunkFilename: "css/[name].css",
}),
],
};
webpack.dev.js
const common = require("./webpack.common");
const { merge } = require("webpack-merge");
module.exports = merge(common, {
mode: "development",
devtool: "inline-source-map",
devServer: {
proxy: {
"/": "http://localhost:8081",
},
port: 8083,
devMiddleware: {
publicPath: "/myapp",
},
},
});
The strange behaviour: If I'm editing files for the page which only a single script has been loaded (single.html), changes are applied immediately. For example changing the background color in the css file is displayed without pagereload. If I'm editing a page where multiple scripts (entry points) are used this is not working anymore. My dev-console logs the following:
[HMR] Update failed: Loading hot update chunk global failed.
(missing: http://localhost:8083/myapp/main.618757b0411fc5552e94.hot-update.js)
The first entry point / chunk (main.js) cannot be loaded, caused by the hash? I need to manually refresh the whole page, to apply changes. I've already searched for solutions and tried to apply this tip
optimization: {
runtimeChunk: {
name: 'single',
},
}
However my dev console does not log any HMR output anymore and nothing happens. It seems like HMR has stopped working in my browser. Webpack is running and bundling it correctly!
Any ideas? Thanks so far and apologizes for this wall of text.
The optimization.runtimeChunk option should be true or 'single' and not an object with name:
optimization: {
runtimeChunk: 'single',
},
As the documentation explains this is an alias for:
optimization: {
runtimeChunk: {
name: 'runtime',
},
},
Also, you'll want to include the runtime.js file on the page, however you need to do that for your set up. It should only be served in the dev environment (so for example, if NODE_ENV is "development").
In my case I have production, server-side script files alongside webpack-dev-server, and needed this option enabled so it would correctly serve runtime.js from the manifest.json:
devServer: {
devMiddleware: {
writeToDisk: true,
},
}

webpack v5 SourceMapDevToolPlugin "exclude" option not working

After upgarding to webpack 5, vendor.js file couldn't be excluded from being source-mapped via SourceMapDevToolPlugin.
// webpack.config.ts - removed other config for brevity
import { Configuration } from 'webpack-dev-server';
export default (env) => {
const config: Configuration = {};
config.mode = 'production';
config.entry = './entry.app.js';
config.output = {
path: path.join(__dirname, '/public'),
pathinfo: true,
filename: '[name].[fullhash].js',
chunkFilename: '[name].[fullhash].js',
};
config.devtool = 'source-map';
config.bail = true;
config.plugins = [
new webpack.SourceMapDevToolPlugin({
filename: '[file].map',
exclude: ['vendor.js'],
}),
];
config.optimization = {
minimize: true,
minimizer: [
new TerserPlugin({
parallel: false,
sourceMap: false,
}),
new CssMinimizerPlugin(),
],
moduleIds: 'deterministic',
splitChunks: {
chunks: 'all',
maxInitialRequests: 100,
minSize: 0,
cacheGroups: {
vendor: {
name: 'vendor',
test: /([/\\]node_modules[/\\]|[/\\]dev[/\\]vendor[/\\])/,
chunks: 'all',
},
},
},
};
return config;
}
// entry.app.js - removed some lines for brevity
import './horrible-asset-loader';
import './setup-for-angular';
import { runApp } from './assets/js/app';
runApp();
// horrible-asset-loader.js
// contains a lot of require statements of npm packages saved into our repository under a vendor folder. crazy i know but I don't know why this was done.
require('ng-bs-daterangepicker/dist/ng-bs-daterangepicker.min.js'); // throwing an error when building because webpack is trying to create a source map for it
// Temporary solution to bundle multiple javascript files into one. This will be replaced by ES6 import.
SourceMapDevToolPlugin exclude config i've tried so far:
// from https://webpack.js.org/plugins/source-map-dev-tool-plugin/#exclude-vendor-maps
exclude: ['vendor.js']
//from https://github.com/webpack/webpack/issues/2431
exclude: /vendor.*.*/
exclude: 'vendor'
// just me desperately trying every possible config
exclude: ['vendor']
exclude: /vendor\.[0-9a-zA-Z]\.js/
exclude: 'vendor.js'
exclude: ['vendor.[chunkhash].js']
exclude: ['vendor.[fullhash].js']
The github issue link mentioned about an issue with UglifyJsPlugin but we aren't using that so I ruled it out.
Although if i set config.devtool to false, the SourceDevToolPlugin config works.
Is there something wrong with my config?
UPDATE: I think i got it now. Looks like i just really have to set devtool to false based on this example: https://webpack.js.org/plugins/source-map-dev-tool-plugin/#basic-use-case
I just thought devtool should only be set to false for development mode because of this note:
If you want to use a custom configuration for this plugin in development mode, make sure to disable the default one. I.e. set devtool: false.
Am I right?
UPDATE 1: Yup! looks like I'm right. I should've read the other comments on the github issue: https://github.com/webpack/webpack/issues/2431#issuecomment-245547872
Sorry for wasting anyone's time.
This was a really silly mistake. I misunderstood the docs for the plugin:
https://webpack.js.org/plugins/source-map-dev-tool-plugin/#basic-use-case
Setting devtool to false fixed the issue.

Webpack 5 - Uncaught ReferenceError: process is not defined

*** Edit - Ignore if you want answer only ***
Seeing as this question is still receiving views and upvotes I feel responsible to share some knowledge after going through the webpack rabbithole and coming out the other end.
If you:
are building a greenfield/early-stage modern javascript project
are considering migrating from create-react-app
don't have much experience with bundling
do not need advanced features like module federation or server side rendering (which doesn't need webpack anymore)
Consider using the next generaton bundlers such as vite/parcel (easy setup), esbuild/rollup (more setup required)
Webpack was/is a fantastic contribution to the frontend world and I'm glad I learned all its intricacies, however, the new bundlers are much faster during development and easier to mantain. It's great when it works but for those inexperienced with it; despite fantastic docs the learning curve can make it a horrible pain to debug.
To clarify, I'm not a maintainer on any of these projects - just a dev who enjoys good tooling. In today's landscape, webpack is comparable to using a sledgehammer to crack a nut.
*** End of Edit ***
Webpack newbie here, I was told by webpack cli that I needed to provide an alias for crypto as webpack no longer includes default node libraries. Now I'm getting this error, other answers haven't helped so much. crypto-browserify is trying to access process.browser. Can anyone shed more light? I was told by cli to install stream-browserify too so i did.
React v17, Babel 7.12.9, webpack 5.6.0
webpack.common.js
const paths = require('./paths');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const dotenv = require('dotenv-webpack');
module.exports = {
entry: [paths.src + '/index.js'],
output: {
path: paths.build,
filename: '[name].bundle.js',
publicPath: '/',
},
plugins: [
new dotenv(),
new CleanWebpackPlugin(),
new CopyWebpackPlugin({
patterns: [
{
from: paths.public,
to: 'assets',
globOptions: {
ignore: ['*.DS_Store'],
},
},
],
}),
new HtmlWebpackPlugin({
title: 'Webpack Boilerplate',
// favicon: paths.src + '/images/favicon.png',
template: paths.src + '/template.html',
filename: 'index.html',
}),
],
resolve: {
fallback: {
crypto: require.resolve('crypto-browserify'),
stream: require.resolve('stream-browserify'),
},
},
module: {
rules: [
// javascript
{
test: /\.js$/,
exclude: /node_modules/,
use: ['babel-loader'],
},
// images
{
test: /\.(?:ico|gif|png|jpg|jpeg)$/i,
type: 'asset/resource',
},
// Fonts and SVGs
{
test: /\.(woff(2)?|eot|ttf|otf|svg|)$/,
type: 'asset/inline',
},
// CSS, PostCSS, and Sass
{
test: /\.(scss|css)$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
esModule: true,
sourceMap: true,
importLoaders: 1,
modules: {
auto: true,
namedExport: true,
},
},
},
{ loader: 'postcss-loader', options: { sourceMap: true } },
{ loader: 'sass-loader', options: { sourceMap: true } },
],
},
],
},
};
webpack.dev.js
const webpack = require('webpack');
const { merge } = require('webpack-merge');
const common = require('./webpack.common');
module.exports = merge(common, {
mode: 'development',
// Control how source maps are generated
devtool: 'inline-source-map',
// Spin up a server for quick development
devServer: {
historyApiFallback: true,
contentBase: paths.build,
open: true,
compress: true,
hot: true,
port: 8080,
},
plugins: [
// Only update what has changed on hot reload
new webpack.HotModuleReplacementPlugin(),
],
});
In webpack 5 automatic node.js polyfills are removed. In the migration docs it is mention that
Try to use frontend-compatible modules whenever possible.
It's possible to manually add a polyfill for a node.js core module.
An error message will give a hint on how to achieve that.
Package authors: Use the browser field in package.json to make a
package frontend-compatible. Provide alternative
implementations/dependencies for the browser.
See this issue.
Now you can refer this PR and check the libs that were removed and install them.
Next add alias for the lib in your webpack config.
For ex.
resolve: {
alias: {
process: "process/browser"
}
}
Update:
This can also be done using ProvidePlugin
package.json
"devDependencies": {
...
"process": "0.11.10",
}
webpack.config.js
module.exports = {
...
plugins: [
new webpack.ProvidePlugin({
process: 'process/browser',
}),
],
}
npm i process was all I needed.
Hope the correction I proposed will be accepted and released soon
I have this problem for HtmlWebpackPlugin, I added 'templateParameters' parameter to HtmlWebpackPlugin and it was fixed for me:
new HtmlWebpackPlugin({
baseUrl: '/',
template: 'app/index.html',
templateParameters(compilation, assets, options) {
return {
compilation,
webpack: compilation.getStats().toJson(),
webpackConfig: compilation.options,
htmlWebpackPlugin: {
files: assets,
options,
},
process,
}
},
chunksSortMode: 'auto',
minify: {
collapseWhitespace: false,
},
cache: true,
}),
1. npm i dotenv-webpack
2. //Define dotenv in your webpack config
const Dotenv = require('dotenv-webpack');
plugins: [
new Dotenv({
path: './.env', // Path to .env file (this is the default)
safe: true, // load .env.example (defaults to "false" which does not use dotenv-safe)
})
],

REACT: WEBPACK: Build to PROD showing local machine path in SourceMap

This is probably a very stupid question but I'm not a REACT developer and I've never worked with it before. So, I had to deploy a React build in my cloud server and I found out after making it work, that the browser's console shows my machine paths.
Can anyone point me out in the right direction here?
Here's the code for my webpack.config.prod.js:
'use strict';
const autoprefixer = require('autoprefixer');
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const ManifestPlugin = require('webpack-manifest-plugin');
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin');
const eslintFormatter = require('react-dev-utils/eslintFormatter');
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
const paths = require('./paths');
const getClientEnvironment = require('./env');
// Webpack uses `publicPath` to determine where the app is being served from.
// It requires a trailing slash, or the file assets will get an incorrect path.
const publicPath = paths.servedPath;
// Some apps do not use client-side routing with pushState.
// For these, "homepage" can be set to "." to enable relative asset paths.
const shouldUseRelativeAssetPaths = publicPath === './';
// Source maps are resource heavy and can cause out of memory issue for large source files.
const shouldUseSourceMap = false;//process.env.GENERATE_SOURCEMAP !== 'false';
// `publicUrl` is just like `publicPath`, but we will provide it to our app
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
// Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz.
const publicUrl = publicPath.slice(0, -1);
// Get environment variables to inject into our app.
const env = getClientEnvironment(publicUrl);
// Assert this just to be safe.
// Development builds of React are slow and not intended for production.
if (env.stringified['process.env'].NODE_ENV !== '"production"') {
throw new Error('Production builds must have NODE_ENV=production.');
}
// Note: defined here because it will be used more than once.
const cssFilename = 'static/css/[name].[contenthash:8].css';
// ExtractTextPlugin expects the build output to be flat.
// (See https://github.com/webpack-contrib/extract-text-webpack-plugin/issues/27)
// However, our output is structured with css, js and media folders.
// To have this structure working with relative paths, we have to use custom options.
const extractTextPluginOptions = shouldUseRelativeAssetPaths
? // Making sure that the publicPath goes back to to build folder.
{ publicPath: Array(cssFilename.split('/').length).join('../') }
: {};
// This is the production configuration.
// It compiles slowly and is focused on producing a fast and minimal bundle.
// The development configuration is different and lives in a separate file.
module.exports = {
// Don't attempt to continue if there are any errors.
bail: true,
// We generate sourcemaps in production. This is slow but gives good results.
// You can exclude the *.map files from the build during deployment.
devtool: shouldUseSourceMap ? 'source-map' : false,
// In production, we only want to load the polyfills and the app code.
entry: [require.resolve('./polyfills'), paths.appIndexJs],
output: {
// The build folder.
path: paths.appBuild,
// Generated JS file names (with nested folders).
// There will be one main bundle, and one file per asynchronous chunk.
// We don't currently advertise code splitting but Webpack supports it.
filename: 'static/js/[name].[chunkhash:8].js',
chunkFilename: 'static/js/[name].[chunkhash:8].chunk.js',
// We inferred the "public path" (such as / or /my-project) from homepage.
publicPath: publicPath,
// Point sourcemap entries to original disk location (format as URL on Windows)
devtoolModuleFilenameTemplate: info =>
path
.relative(paths.appSrc, info.absoluteResourcePath)
.replace(/\\/g, '/'),
},
resolve: {
// This allows you to set a fallback for where Webpack should look for modules.
// We placed these paths second because we want `node_modules` to "win"
// if there are any conflicts. This matches Node resolution mechanism.
// https://github.com/facebookincubator/create-react-app/issues/253
modules: ['node_modules', paths.appNodeModules].concat(
// It is guaranteed to exist because we tweak it in `env.js`
process.env.NODE_PATH.split(path.delimiter).filter(Boolean)
),
// These are the reasonable defaults supported by the Node ecosystem.
// We also include JSX as a common component filename extension to support
// some tools, although we do not recommend using it, see:
// https://github.com/facebookincubator/create-react-app/issues/290
// `web` extension prefixes have been added for better support
// for React Native Web.
extensions: ['.web.js', '.mjs', '.js', '.json', '.web.jsx', '.jsx'],
alias: {
// Support React Native Web
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
'react-native': 'react-native-web',
},
plugins: [
// Prevents users from importing files from outside of src/ (or node_modules/).
// This often causes confusion because we only process files within src/ with babel.
// To fix this, we prevent you from importing files out of src/ -- if you'd like to,
// please link the files into your node_modules/ and let module-resolution kick in.
// Make sure your source files are compiled, as they will not be processed in any way.
new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]),
],
},
module: {
strictExportPresence: true,
rules: [
// TODO: Disable require.ensure as it's not a standard language feature.
// We are waiting for https://github.com/facebookincubator/create-react-app/issues/2176.
// { parser: { requireEnsure: false } },
// First, run the linter.
// It's important to do this before Babel processes the JS.
{ test: /\.jsx?$/, exclude: /node_modules/, loaders: ['babel-loader'] },
{ test: /\.eot(\?v=\d+.\d+.\d+)?$/, loader: 'file-loader' },
{ test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'url-loader?limit=10000&mimetype=application/font-woff' },
{ test: /\.[ot]tf(\?v=\d+.\d+.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/octet-stream' },
{ test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=image/svg+xml' },
{ test: /\.(jpe?g|png|gif)$/i, loader: 'file-loader?name=[name].[ext]' },
{ test: /\.ico$/, loader: 'file-loader?name=[name].[ext]' },
{
test: /(\.sass)$/, loaders: ['style-loader', 'css-loader?sourceMap', 'postcss-loader',
'sass-loader?sourceMap']
},
{
test: /(\.css)$/,
use: [
{ loader: 'style-loader', options: { sourceMap: true } },
{ loader: 'css-loader', options: { sourceMap: true } },
{ loader: 'postcss-loader', options: { sourceMap: true } },
{ loader: 'sass-loader', options: { sourceMap: true } }
]
},
{
test: /(\.scss)$/,
use: [
{ loader: 'style-loader', options: { sourceMap: true } },
{ loader: 'css-loader', options: { sourceMap: true } },
{ loader: 'postcss-loader', options: { sourceMap: true } },
{ loader: 'sass-loader', options: { sourceMap: true } }
]
},
// ** STOP ** Are you adding a new loader?
// Make sure to add the new loader(s) before the "file" loader.
],
},
plugins: [
// Makes some environment variables available in index.html.
// The public URL is available as %PUBLIC_URL% in index.html, e.g.:
// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
// In production, it will be an empty string unless you specify "homepage"
// in `package.json`, in which case it will be the pathname of that URL.
new InterpolateHtmlPlugin(env.raw),
// Generates an `index.html` file with the <script> injected.
new HtmlWebpackPlugin({
inject: true,
template: paths.appHtml,
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
}),
// Makes some environment variables available to the JS code, for example:
// if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`.
// It is absolutely essential that NODE_ENV was set to production here.
// Otherwise React will be compiled in the very slow development mode.
new webpack.DefinePlugin(env.stringified),
// Minify the code.
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
// Disabled because of an issue with Uglify breaking seemingly valid code:
// https://github.com/facebookincubator/create-react-app/issues/2376
// Pending further investigation:
// https://github.com/mishoo/UglifyJS2/issues/2011
comparisons: false,
},
mangle: {
safari10: true,
},
output: {
comments: false,
// Turned on because emoji and regex is not minified properly using default
// https://github.com/facebookincubator/create-react-app/issues/2488
ascii_only: true,
},
sourceMap: shouldUseSourceMap,
}),
// Note: this won't work without ExtractTextPlugin.extract(..) in `loaders`.
new ExtractTextPlugin({
filename: cssFilename,
}),
// Generate a manifest file which contains a mapping of all asset filenames
// to their corresponding output file so that tools can pick it up without
// having to parse `index.html`.
new ManifestPlugin({
fileName: 'asset-manifest.json',
}),
// Generate a service worker script that will precache, and keep up to date,
// the HTML & assets that are part of the Webpack build.
new SWPrecacheWebpackPlugin({
// By default, a cache-busting query parameter is appended to requests
// used to populate the caches, to ensure the responses are fresh.
// If a URL is already hashed by Webpack, then there is no concern
// about it being stale, and the cache-busting can be skipped.
dontCacheBustUrlsMatching: /\.\w{8}\./,
filename: 'service-worker.js',
logger(message) {
if (message.indexOf('Total precache size is') === 0) {
// This message occurs for every build and is a bit too noisy.
return;
}
if (message.indexOf('Skipping static resource') === 0) {
// This message obscures real errors so we ignore it.
// https://github.com/facebookincubator/create-react-app/issues/2612
return;
}
console.log(message);
},
minify: true,
// For unknown URLs, fallback to the index page
navigateFallback: publicUrl + '/index.html',
// Ignores URLs starting from /__ (useful for Firebase):
// https://github.com/facebookincubator/create-react-app/issues/2237#issuecomment-302693219
navigateFallbackWhitelist: [/^(?!\/__).*/],
// Don't precache sourcemaps (they're large) and build asset manifest:
staticFileGlobsIgnorePatterns: [/\.map$/, /asset-manifest\.json$/],
}),
// Moment.js is an extremely popular library that bundles large locale files
// by default due to how Webpack interprets its code. This is a practical
// solution that requires the user to opt into importing specific locales.
// https://github.com/jmblog/how-to-optimize-momentjs-with-webpack
// You can remove this if you don't use Moment.js:
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
],
// Some libraries import Node modules but don't use them in the browser.
// Tell Webpack to provide empty mocks for them so importing them works.
node: {
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty',
},
};
I finally got rid of my problem by setting sourceMap: false in the code below:
{
test: /(\.css)$/,
use: [
{ loader: 'style-loader', options: { sourceMap: false} },
{ loader: 'css-loader', options: { sourceMap: false} },
{ loader: 'postcss-loader', options: { sourceMap: false} },
{ loader: 'sass-loader', options: { sourceMap: false} }
]
},
{
test: /(\.scss)$/,
use: [
{ loader: 'style-loader', options: { sourceMap: false} },
{ loader: 'css-loader', options: { sourceMap: false} },
{ loader: 'postcss-loader', options: { sourceMap: false} },
{ loader: 'sass-loader', options: { sourceMap: false} }
]
},

Require is not defined on reflect-metadata - __webpack_require__ issue

I'm trying to launch my angular app on visual studio but when it starts, it stucks on "Loading..." section.
If i read Chrome's error console i get the following error:
Uncaught ReferenceError: require is not defined at Object. < anonymous > __ webpack_require __
The reflect-metadata contains the following: module.exports = require("reflect-metadata"); , which "require" causes the error.
Here's some of my code...
webpack.config.js
const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const AotPlugin = require('#ngtools/webpack').AotPlugin;
const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin;
var nodeExternals = require('webpack-node-externals');
module.exports = (env) => {
// Configuration in common to both client-side and server-side bundles
const isDevBuild = !(env && env.prod);
const sharedConfig = {
externals: [nodeExternals()], // in order to ignore all modules in node_modules folder
stats: { modules: false },
context: __dirname,
resolve: { extensions: [ '.js', '.ts' ] },
output: {
filename: '[name].js',
publicPath: 'dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
},
module: {
rules: [
{ test: /\.ts$/, use: isDevBuild ? ['awesome-typescript-loader?silent=true', 'angular2-template-loader', 'angular2-router-loader'] : '#ngtools/webpack' },
{ test: /\.html$/, use: 'html-loader?minimize=false' },
{ test: /\.css$/, use: [ 'to-string-loader', 'style-loader', isDevBuild ? 'css-loader' : 'css-loader?minimize' ] },
{ test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' }
]
},
plugins: [new CheckerPlugin()]
};
// Configuration for client-side bundle suitable for running in browsers
const clientBundleOutputDir = './wwwroot/dist';
const clientBundleConfig = merge(sharedConfig, {
entry: { 'main-client': './ClientApp/boot.browser.ts' },
output: { path: path.join(__dirname, clientBundleOutputDir) },
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./wwwroot/dist/vendor-manifest.json')
})
].concat(isDevBuild ? [
// Plugins that apply in development builds only
new webpack.SourceMapDevToolPlugin({
filename: '[file].map', // Remove this line if you prefer inline source maps
moduleFilenameTemplate: path.relative(clientBundleOutputDir, '[resourcePath]') // Point sourcemap entries to the original file locations on disk
})
] : [
// Plugins that apply in production builds only
new webpack.optimize.UglifyJsPlugin(),
new AotPlugin({
tsConfigPath: './tsconfig.json',
entryModule: path.join(__dirname, 'ClientApp/app/app.browser.module#AppModule'),
exclude: ['./**/*.server.ts']
})
])
});
// Configuration for server-side (prerendering) bundle suitable for running in Node
const serverBundleConfig = merge(sharedConfig, {
resolve: { mainFields: ['main'] },
entry: { 'main-server': './ClientApp/boot.server.ts' },
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./ClientApp/dist/vendor-manifest.json'),
sourceType: 'commonjs2',
name: './vendor'
})
].concat(isDevBuild ? [] : [
// Plugins that apply in production builds only
new AotPlugin({
tsConfigPath: './tsconfig.json',
entryModule: path.join(__dirname, 'ClientApp/app/app.server.module#AppModule'),
exclude: ['./**/*.browser.ts']
})
]),
output: {
libraryTarget: 'commonjs',
path: path.join(__dirname, './ClientApp/dist')
},
target: 'node',
devtool: 'inline-source-map'
});
return [clientBundleConfig, serverBundleConfig];
};
Searching on the internet, all of the troubleshooting suggests doing something on the systemjs.config file but mine is not an angular-cli app so I can't do it.
UPDATES SECTION
UPDATE #1
Looks like the problem is caused by webpack-node-externals executed in browser mode.
Got to find another way for that.
Got any troubleshooting or potential solution suggestion?
Thanks in advance!
UPDATE #2
I've made it, see my answer below
GOT IT!
The issue was caused by webpack-node-externals used on my common configuration.
See my question and my answer to my own question at the following: Webpack - Excluding node_modules with also keep a separated browser and server management for more details.
So, in a nutshell, the steps that I followed are these:
Installing requireJS ==> http://requirejs.org/docs/node.html
Removing externals: [nodeExternals()], // in order to ignore all modules in node_modules folder from my common webpack configuration and adding it under my server configuration (done before my question, but it's a really important step) [see webpack.config.js content in the question linked right above in this answer or in the snippet below]
Adding target: 'node', before my externals point above, under my server side section (done before my question, but it's a really important step) [see webpack.config.js content in the question linked right above in this answer or in the snippet below]
This makes sure that browser side keeps target:'web' (default target), and target becomes node just for the server.
launched webpack config vendor command manually from powershell webpack --config webpack.config.vendor.js
launched webpack config command manually from powershell webpack --config webpack.config.js
That worked for me! Hope It will works also for anyone else reading this question and encountering this issue!
webpack.config.js content:
const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const AotPlugin = require('#ngtools/webpack').AotPlugin;
const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin;
var nodeExternals = require('webpack-node-externals');
module.exports = (env) => {
// Configuration in common to both client-side and server-side bundles
const isDevBuild = !(env && env.prod);
const sharedConfig = {
//removed from here, moved below.
//externals: [nodeExternals()], // in order to ignore all modules in node_modules folder
stats: { modules: false },
context: __dirname,
resolve: { extensions: [ '.js', '.ts' ] },
output: {
filename: '[name].js',
publicPath: 'dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
},
module: {
rules: [
{ test: /\.ts$/, use: isDevBuild ? ['awesome-typescript-loader?silent=true', 'angular2-template-loader', 'angular2-router-loader'] : '#ngtools/webpack' },
{ test: /\.html$/, use: 'html-loader?minimize=false' },
{ test: /\.css$/, use: [ 'to-string-loader', 'style-loader', isDevBuild ? 'css-loader' : 'css-loader?minimize' ] },
{ test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' }
]
},
plugins: [new CheckerPlugin()]
};
// Configuration for client-side bundle suitable for running in browsers
const clientBundleOutputDir = './wwwroot/dist';
const clientBundleConfig = merge(sharedConfig, {
entry: { 'main-client': './ClientApp/boot.browser.ts' },
output: { path: path.join(__dirname, clientBundleOutputDir) },
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./wwwroot/dist/vendor-manifest.json')
})
].concat(isDevBuild ? [
// Plugins that apply in development builds only
new webpack.SourceMapDevToolPlugin({
filename: '[file].map', // Remove this line if you prefer inline source maps
moduleFilenameTemplate: path.relative(clientBundleOutputDir, '[resourcePath]') // Point sourcemap entries to the original file locations on disk
})
] : [
// Plugins that apply in production builds only
new webpack.optimize.UglifyJsPlugin(),
new AotPlugin({
tsConfigPath: './tsconfig.json',
entryModule: path.join(__dirname, 'ClientApp/app/app.browser.module#AppModule'),
exclude: ['./**/*.server.ts']
})
])
});
// Configuration for server-side (prerendering) bundle suitable for running in Node
const serverBundleConfig = merge(sharedConfig, {
resolve: { mainFields: ['main'] },
entry: { 'main-server': './ClientApp/boot.server.ts' },
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./ClientApp/dist/vendor-manifest.json'),
sourceType: 'commonjs2',
name: './vendor'
})
].concat(isDevBuild ? [] : [
// Plugins that apply in production builds only
new AotPlugin({
tsConfigPath: './tsconfig.json',
entryModule: path.join(__dirname, 'ClientApp/app/app.server.module#AppModule'),
exclude: ['./**/*.browser.ts']
})
]),
output: {
libraryTarget: 'commonjs',
path: path.join(__dirname, './ClientApp/dist')
},
//added target and externals HERE, in order to prevent webpack to read node_modules
//this also prevents fake-positives parsing errors
target: 'node',
externals: [nodeExternals()], // in order to ignore all modules in node_modules folder,
devtool: 'inline-source-map'
});
return [clientBundleConfig, serverBundleConfig];
};

Categories

Resources