Exclude a module from webpack bundle - javascript

I'd like the same functionality like RequireJS empty: http://requirejs.org/docs/optimization.html#empty
My use-case is that I include jquery-migrate in development, but I'd like to exclude this when built for production.
Using IgnorePlugin just makes it not included, and when requireing it in the code, it then throws an error (Uncaught Error: Cannot find module "jquery-migrate").
What I'd like to happen is for it to just return undefined, or something of the like (like empty: in RequireJS). Id like to not touch the import in the code, just configuring it to return undefined.
EDIT: Using NormalModuleReplacementPlugin works, if I point the replacement to an empty file. But keeping an empty file around just for this seems unnecessary.

I use the null-loader for blanking out modules.
The noop-loader can be used for a less awkward if-else in the config.
Try:
rules: [{
test: /jquery-migrate/,
use: IS_DEV ? 'null-loader' : 'noop-loader'
}]

You can try to make a resolve.alias in webpack.config:
resolve: {
alias: {
"jquery-migrate": process.env.NODE_ENV === 'production' ? "empty-module": "jquery-migrate"
}
}

Use Webpack's DefinePlugin in combination with the normal production plugins (Dedupe and Uglify).
Then in your code you can write:
if(DEBUG) {
var test = require('test');
alert(test);
}
And when it's built in production, the DEBUG will be replaced with a literal if(false) { ... } which will be completely removed by the uglify plugin, so test will only be required in a debug build.
Here's a sample Grunt task config for grunt-webpack that has development and production targets for the task:
development: {
devtool: "sourcemap",
output: {
pathinfo: true,
},
debug: true,
production: false,
plugins: [
new webpack.DefinePlugin({
DEBUG: true,
PRODUCTION: false
})
]
},
production: {
plugins: [
new webpack.DefinePlugin({
DEBUG: false,
PRODUCTION: true
}),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin({
output: {
comments: false,
}
})
]
},

Related

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

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.

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)
})
],

Uglify JS Webpack plugin for Webpack Stream (Gulp + Webpack)

I am trying to use Gulp + Webpack workflow
Most Things are working at https://github.com/IamManchanda/gulp-webpack/
But when I am trying to Implement UglifyjsWebpackPlugin as per the mentioned docs, it just doesn't seem to work. I don't get any errors, what I get is simply the non-uglified code!
Here is my code for same => https://github.com/IamManchanda/gulp-webpack/pull/7/
In fact to be more specific, here is my config.production.js
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
mode: 'production',
devtool: 'source-map',
output: {
filename: 'scripts.js',
},
optimization: {
minimizer: [
new UglifyjsWebpackPlugin({
sourceMap: true,
}),
],
},
};
Am I missing something? Do I need some more RTFM? Can you guys help me here
Let me know if you need any other details. Thanks in Advance.
Edit: Here is the video demo of the same issue: https://drive.google.com/file/d/1Xa1E3vnXR2_fFuqZ8b5Hu4-kMb2gD2FT/view
Please change output filename to scripts.min.js, and use property compress as true.
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
mode: 'production',
devtool: 'source-map',
output: {
filename: 'scripts.min.js',
},
optimization: {
minimizer: [
new UglifyjsWebpackPlugin({
sourceMap: true,
minify(file, sourceMap) {
// https://github.com/mishoo/UglifyJS2#minify-options
const uglifyJsOptions = { /* your `uglify-js` package options */ };
if (sourceMap) {
uglifyJsOptions.sourceMap = {
content: sourceMap,
};
}
return require('uglify-js').minify(file, uglifyJsOptions);
}
}),
],
},
};
So as I needed this on urgent basis, I have used gulp to do the job instead of webpack ... That being said ... still looking for webpack solution
Anyways here is my Gulp based (gulpfile.js) Solution => https://github.com/IamManchanda/gulp-webpack/pull/8
1.
yarn add --dev gulp-uglify
2.
const gulpUglify = require('gulp-uglify');
3.
...((mode === 'production') ? [gulpUglify()] : []),
I think what matters for me right now is that this works for me :)
Just define
new UglifyjsWebpackPlugin in plugins
{
'plugins': [
new UglifyJsPlugin({
'sourceMap': false,
'parallel': true
})
]
}
Don't use optimization.minimizer

How to execute karma index.html file before all others?

I have the following karma config file (relevant properties):
files: [
{ pattern: './src/*.html', watched: true, served: true, included: false },
// polyfill for es6 Promise
'node_modules/es6-promise/dist/es6-promise.auto.js',
// polyfill for fetch.js
'node_modules/whatwg-fetch/fetch.js',
'./src/**/*.ts'
],
preprocessors: {
'**/*.html': ['html2js'],
'**/*.ts': 'karma-typescript',
'karma-babel-preprocessor': ['babel']
},
I'm using an ES6 Module project (no React, Angular2+ setup) and trying to set up my tests to run properly.
The main problem is that in my .ts file (not spec.ts --> file aimed for testing only) I have a doccument.getElementById('').someAttribute which breaks at test run time because it's null. The reason this happens is because index.html hasn't been set up yet by karma.
How do I solve the problem of index.html first being built and then all other .ts files...
Error after running npm test: *
"message": "Uncaught TypeError: Cannot set property 'innerHTML' of
null\nat
Have you tried instead of 'karma-babel-preprocessor' and 'karma-typescript' to use 'webpack' with transpilation either Babel or Typescript?
Here is https://www.npmjs.com/package/awesome-typescript-loader that can be used for TypeScript handling with webpack.
There might be kind of conflict also of using both Babel and Typescript because Typescript can transpile without babel but it is something that you can handled in webpack config. Here is how 'karma.conf' might look like with Babel:
const webpack = require('webpack');
module.exports = function (config) {
var configuration = {
browsers: ['Chrome'],
files: [
{ pattern: 'test/**/*.js', watched: true },
],
frameworks: ['jasmine'],
preprocessors: {
'test/**/*.js': ['webpack'],
},
webpack: {
module: {
loaders: [
{ test: /\.js/, exclude: /node_modules/, loader: 'babel-loader' }
]
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('test')
}
})
],
watch: true
},
webpackServer: {
noInfo: true
}
};
config.set(configuration);
};

Categories

Resources