I recently updated to Webpack 5 from Webpack 4, earlier I had a function on window object in index.js such that it looked something like
index.js
window.someFunction = function (...arguments) {
// function body
}
when this index.js gets bundled I can find this same function in common.bundle.js file.
and my index.html looks something like this
index.html
<head>
// rest of the head stuff
<script src="./dist/common.bundle.js"></script>
</head>
<body>
<script type="text/javascript">
someFunction(); // calling someFunction from the window object
// Also tried using window.someFunction() still doesn't work
</script>
</body>
In console I get ReferenceError: someFunction is not defined
and I am not able to print the function defination in chrome console when I type window.someFunction which was working in Webpack 4 as expected.
How do I attach my functions to window object in Webpack 5, and how do I go about accessing it?
webpack.config.js
const path = require("path");
const webpack = require("webpack");
module.exports = (env) => {
return {
mode: "development",
devtool: "source-map",
entry: {
common: "./index.js",
},
output: {
pathinfo: true,
path: path.join(__dirname, "dist"),
filename: "[name].bundle.js",
},
plugins: [
new webpack.DefinePlugin({
"process.env.NODE_ENV": JSON.stringify("development"),
}),
],
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: "babel-loader",
options: {
cacheDirectory: true,
babelrc: false,
presets: [
[
"#babel/env",
{
modules: false,
loose: true,
targets: {
browsers: [">0.25%", "not ie 11", "not op_mini all"],
},
},
],
"#babel/react",
],
plugins: [
[
"#babel/plugin-proposal-class-properties",
{
loose: true,
},
],
["#babel/plugin-transform-runtime"],
],
},
},
},
{
test: /\.css$/,
include: /node_modules/,
use: [{ loader: "style-loader" }, { loader: "css-loader" }],
},
],
},
resolve: {
extensions: [".js", ".jsx"],
modules: [path.resolve(__dirname, "node_modules")],
fallback: {
buffer: false,
fs: false,
tls: false,
net: false,
path: false,
zlib: false,
http: false,
https: false,
stream: false,
crypto: false,
},
},
optimization: {
// namedModules: true,
// namedChunks: true,
minimize: false,
// minimizer: [new TerserPlugin()],
runtimeChunk: "single",
moduleIds: "deterministic",
chunkIds: "deterministic",
nodeEnv: "development",
flagIncludedChunks: false,
concatenateModules: false,
splitChunks: {
hidePathInfo: false,
minSize: 20000,
maxAsyncRequests: Infinity,
maxInitialRequests: Infinity,
chunks: "all",
// maxSize: 0,
minChunks: 1,
automaticNameDelimiter: "~",
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: "other.bundle",
chunks: "all",
minChunks: 2,
},
defaultVendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
},
},
emitOnErrors: true,
checkWasmTypes: false,
removeAvailableModules: false,
},
performance: {
hints: "warning",
},
stats: {
all: false,
assets: true,
builtAt: true,
cachedAssets: false,
cachedModules: true,
chunkGroups: true,
colors: true,
env: true,
errors: true,
hash: true,
logging: "info",
timings: true,
modules: true,
outputPath: true,
performance: true,
errorsCount: true,
warnings: false,
warningsCount: true,
publicPath: true,
reasons: true,
ids: true,
version: true,
},
cache: {
type: "filesystem",
version: "1.0.0",
store: "pack",
name: "AppBuildCache",
maxMemoryGenerations: 1,
idleTimeout: 60000,
idleTimeoutAfterLargeChanges: 1000,
idleTimeoutForInitialStore: 0,
hashAlgorithm: "md4",
cacheLocation: path.resolve(__dirname, ".cache"),
},
externals: [
{
react: "React",
"react-dom": "ReactDOM",
jquery: "jQuery",
},
],
};
};
Try to add node.global: true to your config:
node: {
global: true
}
DoneDel0's comment was the correct solution for me.
node: {
global: true
}
The reasoning behind this is webpack 5 does no longer include a polyfills for node modules, so you have to manually set each.
https://webpack.js.org/configuration/node/#nodeglobal
However its good to note that the docs does suggest using ProvidePlugin instead of global.
Thank you for the answers, the issue turned out exactly to be due to missing polyfills for node core modules.
In my case the I had to provide polyfill for process using ProvidePlugin.
I did the same by adding below to my config
new webpack.ProvidePlugin({
process: "process/browser",
})
I added
node: {
global: true
}
but still the function is undefined in window object.
Related
Webpack version: 4.35.3
All compilation is successful.
My code after compilation in bundle.css is not minify.
I try to use minimize: true in text-webpack-plugin, but it not working.
For compile I use command in command line: webpack in my working directory
What am I doing wrong?
Why does MiniCssExtractPlugin not work, maybe because of resolve-url-loader?
My wepback config:
const AssetsWebpackPlugin = require('assets-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const FaviconsWebpackPlugin = require('favicons-webpack-plugin')
const FileManagerPlugin = require('filemanager-webpack-plugin')
const { PATH } = require('../constants')
module.exports = {
mode: 'production',
output: {
path: PATH.publicFolder,
publicPath: '/',
filename: 'static/react/js/[name].[contenthash].js',
chunkFilename: 'static/react/js/[name].[contenthash].js',
sourceMapFilename: 'static/react/js/[name].[contenthash].js.map',
jsonpFunction: 'reactJsonpFunction',
},
performance: {
hints: false,
},
watch: false,
devtool: 'source-map',
plugins: [
new DefinePlugin({
NODE_ENV: JSON.stringify('production'),
}),
new AssetsWebpackPlugin({
filename: 'static/react/assets.json',
path: PATH.publicFolder,
}),
new MiniCssExtractPlugin({
filename: 'static/react/css/common.css',
}),
new FaviconsWebpackPlugin({
logo: PATH.favicon,
prefix: 'static/react/icons/',
emitStats: false,
statsFilename: 'iconstats.json',
background: '#fff',
persistentCache: true,
inject: true,
icons: {
android: true,
appleIcon: true,
appleStartup: true,
coast: false,
favicons: true,
firefox: true,
opengraph: false,
twitter: false,
yandex: false,
windows: false,
},
}),
new FileManagerPlugin({
onStart: {
delete: ['../jrp-web-app/static/react/'],
},
onEnd: {
mkdir: ['../jrp-web-app/static/react/'],
copy: [
{
source: 'public/static/react',
destination: '../jrp-web-app/static/react',
},
],
},
}),
],
module: {
rules: [
{
test: /\.(png|jpg|gif|svg|woff|woff2)$/,
use: [
{
loader: 'file-loader',
options: {
name: 'static/react/images/[name]-[hash:8].[ext]',
},
},
],
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
sourceMap: false,
},
},
'resolve-url-loader',
{
loader: 'postcss-loader',
options: {
sourceMap: false,
config: {
path: PATH.postcssConfig,
},
},
},
],
},
],
},
}```
I have a .ts file that contains a function, and I want to compile this file into .js file via webpack to be loaded in index.html.
I need this function to be globally available in index.html, or within a module
index.html
<script src="./myfile.js"></scrit>
<script>
console.log(myfunction);
// ----> error: myfunction is not defined
</scrit>
<script type="module">
import { myfunction } from './myfile'
console.log({myfunction})
// ----> error: requested module './myfile.js' does not provide an export named 'myfunction'
</script>
myfile.ts
export myfunction = function(){}
webpack.config
{
mode: 'development',
devtool: false,
target: [ 'web', 'es5' ],
profile: false,
resolve: {
roots: [Array],
extensions: [Array],
symlinks: false,
modules: [Array],
mainFields: [Array],
plugins: [Array],
alias: [Object]
},
resolveLoader: { symlinks: true, modules: [Array] },
context: '/home/sh_eldeeb_2010/#eng-dibo/dibo/projects/ngx-cms',
entry: {
main: [Array],
'polyfills-es5': [Array],
polyfills: [Array],
styles: [Array],
scripts: './scripts.ts'
},
output: {
clean: true,
path: './dist',
publicPath: '',
filename: '[name].js',
chunkFilename: '[name]-es2015.js',
crossOriginLoading: false,
trustedTypes: 'angular#bundler',
library: undefined,
libraryTarget: 'commonjs2'
},
watch: false,
watchOptions: { poll: undefined, ignored: '**/$_lazy_route_resources' },
performance: { hints: false },
ignoreWarnings: [
/System.import\(\) is deprecated and will be removed soon/i,
/Failed to parse source map from/,
/Add postcss as project dependency/
],
module: {
strictExportPresence: true,
rules: [Array],
noParse: /\/native-require.js$/
},
experiments: { syncWebAssembly: true, asyncWebAssembly: true },
cache: false,
optimization: {
minimizer: [Array],
moduleIds: 'deterministic',
chunkIds: 'deterministic',
emitOnErrors: false,
runtimeChunk: 'single',
splitChunks: [Object]
},
plugins: [
[ContextReplacementPlugin],
[DedupeModuleResolvePlugin],
[ProgressPlugin],
[LicenseWebpackPlugin],
[CommonJsUsageWarnPlugin],
[AnyComponentStyleBudgetChecker],
[Object],
[MiniCssExtractPlugin],
SuppressExtractedTextChunksWebpackPlugin {},
[NgBuildAnalyticsPlugin],
[AngularWebpackPlugin],
[FilterErrors]
],
node: false,
stats: {
all: false,
colors: true,
hash: true,
timings: true,
chunks: true,
builtAt: true,
warnings: true,
errors: true,
assets: true,
cachedAssets: true,
ids: true,
entrypoints: true
},
externals: []
},
entry: {
myfile: './myfile.ts'
}
}
I have vue application with the cli. I want to use uglifyjs plugin.
So I add this code to my vue.config.js:
configureWebpack: {
optimization: {
minimizer: [
new UglifyJsPlugin({
uglifyOptions: {
warnings: false,
parse: {},
compress: {},
mangle: true, // Note `mangle.properties` is `false` by default.
output: null,
toplevel: false,
nameCache: null,
ie8: false,
keep_fnames: false,
},
}),
],
},
I want to compress all the css that exist in *.scss and *.vue files. How to configure UglifyJsPlugin to compress and minify? for example, I have this selector: .some-thing the output should be: .x.
Here what is not working:
app.vue
<template>
<div class="some">appp</div>
</template>
<script>
export default {
name: 'App',
};
</script>
<style lang="scss" scoped>
.some { border:1px solid red;}
</style>
I run this command (which vue cli build):
npm run build (for production).
My full vue.config.js:
const merge = require('lodash/merge');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
css: {
loaderOptions: {
sass: {
prependData: `
#import "~#/sass/mixins.scss";
`,
},
},
},
configureWebpack: {
optimization: {
minimizer: [
new UglifyJsPlugin({
uglifyOptions: {
warnings: false,
parse: {},
compress: {},
mangle: true, // Note `mangle.properties` is `false` by default.
output: null,
toplevel: false,
nameCache: null,
ie8: false,
keep_fnames: false,
},
}),
],
},
},
};
The css/app.css is with the following content:
.some[..] {border:1px solid red;}...
** Edit ** After #Tony Ngo answer:
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
module.exports = {
css: {
loaderOptions: {
sass: {
prependData: `
#import "~#/sass/mixins.scss";
`,
},
},
},
configureWebpack: {
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: false,
extractComments: 'all',
uglifyOptions: {
compress: true,
output: null,
},
}),
new OptimizeCSSAssetsPlugin({
cssProcessorOptions: {
safe: true,
discardComments: {
removeAll: true,
},
},
}),
],
},
plugins: [
new CompressionPlugin({
test: /\.(js|css)/,
}),
new UglifyJsPlugin(),
],
},
chainWebpack: (config) => {
// nothing here yet
},
};
Still .some is in my app.css bundle. I want to minify and compress so I expect to something like .x
You can view my full code here
Here is the base setup you will need to uglify your code
module.exports = {
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: false,
extractComments: 'all',
uglifyOptions: {
compress: true,
output: null
}
}),
new OptimizeCSSAssetsPlugin({
cssProcessorOptions: {
safe: true,
discardComments: {
removeAll: true,
},
},
})
]
},
plugins: [
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
}),
new CompressionPlugin({
test: /\.(js|css)/
}),
new UglifyJsPlugin(),
],
module: {
rules: [{
test: /\.scss$/,
use: [
'style-loader',
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
minimize: true,
sourceMap: true
}
},
{
loader: "sass-loader"
}
]
},
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: ["babel-loader", "eslint-loader"]
},
{
test: /\.(jpe?g|png|gif)$/i,
loader: "file-loader"
},
{
test: /\.(woff|ttf|otf|eot|woff2|svg)$/i,
loader: "file-loader"
}
]
}
};
I'm trying to reduce the size of my bundle.js. Here is my webpack config for production:
module.exports = () => {
return {
entry: ['babel-polyfill', './src/app.js'],
output: {
path: path.join(__dirname, 'public', 'dist'),
filename: 'bundle.js',
chunkFilename: '[name].js'
},
optimization: {
runtimeChunk: true,
splitChunks: {
chunks: 'all',
minSize: 50000,
maxSize: 250000,
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
name: "vendors",
priority: -10
},
}
},
minimizer: [
new UglifyJSPlugin({
uglifyOptions: {
parse: {
ecma: 8,
},
compress: {
ecma: 5,
warnings: false,
comparisons: false,
},
mangle: {
safari10: true,
},
output: {
ecma: 5,
comments: false,
ascii_only: true,
},
},
cache: true,
parallel: true,
sourceMap: true
}),
new OptimizeCSSAssetsPlugin({})
]
},
module: {
rules: [{
loader: 'babel-loader',
test: /\.js$/,
exclude: /node_modules/
},{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader']
}]
},
plugins: [
new webpack.DefinePlugin({/*env variables*/}),
new MiniCssExtractPlugin({
filename: 'styles.css',
}),
new HtmlWebpackPlugin({ template: 'index.ejs', filename: path.join(__dirname, 'public', 'index.html')}),
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
],
devtool: 'source-map'
};
};
My app is structured like a classic React/Redux app followed:
|-src
|-|-app.js
|-|-actions
|-|-components
|-|-helpers
|-|-routers
|-|-selectors
|-|-store
With this webpack config, I managed to extract the css out and split into chunks of maximum 250kb. I also reduced the size of moment.
After all this effort, my entrypoint is still a total of 583Kb.
What else I can do?
I tried lazy loading part of the application but it didn't work. So if you have example of lazy loading for a React app, that would be great.
I have webpack 6.0.1. Based on the documentation I use the following plugins:
webpack.optimize.ModuleConcatenationPlugin() - concatenate the scope
of all your modules into one closure and allow for your code to have
a faster execution time in the browser
webpack.HashedModuleIdsPlugin() - cause hashes to be based on the
relative path of the module, generating a four character string as
the module id
webpack.optimize.OccurrenceOrderPlugin() - vary the
distribution of the ids to get the smallest id length for often used
ids
webpack.NoEmitOnErrorsPlugin() - skip the emitting phase
whenever there are errors while compiling. This ensures that no
assets are emitted that include errors
I tested, use the following configuration ideas for webpack.config.js. You can test your configuration against these settings:
//webpack.config.js
module.exports = {
...
devtool: 'cheap-module-source-map',
...
plugins : [
...
new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production') }),
new webpack.optimize.ModuleConcatenationPlugin(),
new webpack.HashedModuleIdsPlugin({
hashFunction: 'sha256',
hashDigest: 'hex',
hashDigestLength: 4
}),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
],
...
optimization: {
namedModules: false,
namedChunks: false,
nodeEnv: 'production',
flagIncludedChunks: true,
occurrenceOrder: true,
sideEffects: true,
usedExports: true,
concatenateModules: true,
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: 'vendor',
chunks: 'all'
}
},
minSize: 30000,
maxAsyncRequests: 5,
maxAsyncRequests: 3,
},
noEmitOnErrors: true,
minimize: true,
minimizer: [
// we specify a custom UglifyJsPlugin here to get source maps in production
new UglifyJsPlugin({
cache: true,
parallel: true,
uglifyOptions: {
compress: false,
ecma: 6,
mangle: true
},
sourceMap: true
})
],
removeAvailableModules: true,
removeEmptyChunks: true,
mergeDuplicateChunks: true,
},
...
}
I have preact project, it work fine, but webpack is rebuilding the project when I edit file api/index.php and fail when I didn't save the file in emacs because of .#index.php file.
How can I ignore api directory or only process files from app directory? I need to copy file from root directory so I can't use context because webpack don't see files like index.html or .htaccess that's inside root directory.
Here is my webpack config file:
module.exports = {
entry: {
app: path.resolve('./app') + '/app.jsx'
},
output: {
path: path.resolve('./dist'),
filename: "[name].js"
},
plugins: ([
new webpack.optimize.CommonsChunkPlugin({
name: "vendor",
minChunks: isNodeModule
}),
new webpack.DefinePlugin({
PRODUCTION: ENV === 'production'
}),
new CopyWebpackPlugin([
{from: 'index.html'},
{from: '.htaccess'},
{from: 'config.json'},
{from: 'api', to: 'api'}
])
]).concat(ENV==='production' ? [
new webpack.optimize.UglifyJsPlugin({
output: {
comments: false
},
compress: {
unsafe_comps: true,
properties: true,
keep_fargs: false,
pure_getters: true,
collapse_vars: true,
unsafe: true,
warnings: false,
screw_ie8: true,
sequences: true,
dead_code: true,
drop_debugger: true,
comparisons: true,
conditionals: true,
evaluate: true,
booleans: true,
loops: true,
unused: true,
hoist_funs: true,
if_return: true,
join_vars: true,
cascade: true,
drop_console: true
}
})
] : []),
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015']
}
},
{
test: /\.css$/,
loaders: ['style-loader', 'css-loader']
}
]
},
resolve: {
extensions: ['.jsx', '.js', '.json']
},
devServer: {
historyApiFallback: true,
open: true
}
};
EDIT: it seems that this in not related to dev-server because I can't run webpack too, when I have unsaved file in Emacs.