Adding a webpack plugin inside a Next.js project - javascript

I'm trying to add the Webpack Bundle Analyzer to my Next.js app. I tried updating my next.config.js as follows:
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
plugins: [new BundleAnalyzerPlugin()],
};
module.exports = nextConfig;
But this throwing this error:
Invalid next.config.js options detected: The root value has an unexpected property, plugins, which is not in the list of allowed properties (amp, analyticsId, assetPrefix, basePath, cleanDistDir, compiler, compress, crossOrigin, devIndicators, distDir, env, eslint, excludeDefaultMomentLocales, experimental, exportPathMap, generateBuildId, generateEtags, headers, httpAgentOptions, i18n, images, modularizeImports, onDemandEntries, optimizeFonts, output, outputFileTracing, pageExtensions, poweredByHeader, productionBrowserSourceMaps, publicRuntimeConfig, reactStrictMode, redirects, rewrites, sassOptions, serverRuntimeConfig, skipMiddlewareUrlNormalize, skipTrailingSlashRedirect, staticPageGenerationTimeout, swcMinify, trailingSlash, transpilePackages, typescript, useFileSystemPublicRoutes, webpack).

You are getting this error because you are not using the correct way to customize Webpack inside next.config.js. This is how you would do it:
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
webpack: (config, { dev }) => {
// the condition is to have the plugin on build time, not to perturb live refresh
!dev && config.plugins.push(new BundleAnalyzerPlugin());
return config;
},
};
module.exports = nextConfig;
For more, check out the doc, at Custom Webpack Config.

Related

Vue 3 - How to add Polyfills to ChainWebpack

Using Vue 3, how do I add path-browserify to vue.config.js?
module.exports = {
chainWebpack: config => {}
}
I am receiving the following error when compiling:
BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.
If you want to include a polyfill, you need to:
- add a fallback 'resolve.fallback: { "path": require.resolve("path-browserify") }'
- install 'path-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
resolve.fallback: { "path": false }
Webpack 5 removed some things that Webpack 4 included in the bundle.
To get it all back in a vue3 app you can use the polyfill plugin.
From a vanilla create-vue-app with babel:
> npm i node-polyfill-webpack-plugin
babel.config.js
module.exports = {
presets: [
'#vue/cli-plugin-babel/preset'
]
}
vue.config.js
const { defineConfig } = require("#vue/cli-service");
const NodePolyfillPlugin = require("node-polyfill-webpack-plugin");
module.exports = defineConfig({
transpileDependencies: true,
configureWebpack: {
plugins: [new NodePolyfillPlugin()],
optimization: {
splitChunks: {
chunks: "all",
},
},
},
});
With #Zack's help, using chainWebpack:
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin')
module.exports = {
chainWebpack: config => {
config.plugin('polyfills').use(NodePolyfillPlugin)
},
}

Use latest terser-webpack-plugin with Webpack5

According to this link (Terser documentation) if you are using latest Webpack 5, you don't need to install the Terser plugin as it is included in Webpack 5 out of the box. However, I am having a hard time to get this working.
If I remove the terser-webpack-plugin from my packages.json file and I try to use it like this (see below webpack.production.js), I get build errors like this:
[webpack-cli] Failed to load 'D:\Project\React\MyApp\config\webpack.production.js' config
[webpack-cli] Error: Cannot find module 'terser-webpack-plugin'
webpack.production.js
const TerserPlugin = require('terser-webpack-plugin');
const webpack = require('webpack');
const { merge } = require('webpack-merge');
module.exports = merge(commonCfg, {
......
optimization: {
minimize: true,
minimizer: [new TerserPlugin({
cache: false,
parallel: false,
sourceMap: true,
})]
},
Now, if I include the latest terser-webpack-plugin version (5.1.1) on my package.json and run my build, I get the following error message:
[webpack-cli] Failed to load 'D:\Project\React\MyApp\config\webpack.production.js' config
[webpack-cli] Invalid options object. Terser Plugin has been
initialized using an options object that does not match the API
schema.
options has an unknown property 'sourceMap'. These properties are valid: object { test?, include?, exclude?, terserOptions?,
extractComments?, parallel?, minify? }
The only way I can make this work is keeping terser-webpack-plugin on version 4.2.X.
Is there a way I can make this work with latest Terser version? Or maybe I misunderstood the documentation?
Hi here is how i resolved the Terserof Webpack 5
Before Webpack 5:
minimizer: [
new TerserPlugin({
terserOptions: {
mangle: {
compress: {},
},
}
})
]
After Webpack 5:
minimizer: [
(compiler) => {
const TerserPlugin = require('terser-webpack-plugin');
new TerserPlugin({
terserOptions: {
compress: {},
}
}).apply(compiler);
},
]
you can read more about it here https://webpack.js.org/configuration/optimization/
and to check the terser option check this url
https://github.com/webpack-contrib/terser-webpack-plugin#terseroptions
here is link to my article with more migration error problem solved
https://medium.com/#arianpopalyar/webpack-4-to-webpack-5-migration-9bc683d2bc72
I have tried the below configuration with webpack version 5.25.0, no need install terser-webpack-plugin and it's worked for me.
optimization: {
minimizer: [(compiler) => {
return () => {
return {
terserOptions: {
mangle: {
reserved: ['Td', 'Tr', 'Th', 'Thead']
}
}
}
}
}]
}

Using webpack for copying file if it is on localhost, else minifying

I am new to Webpack.
My team is using Golang for the server, and starting to use ReactJS + MobX on the front end. We use Webpack to bundle/transpile all the code into one bundle file per page. (It is multipage application.)
My PM has me looking into moving all this front-end code from static to a new folder called src, and to do the following:
setup the environment such that:
if running localhost, simply copy the files to that folder (we're debugging it)
else, minify the files to that folder (we don't want the end user to be able to reverse-engineer our stuff/see its source code)
Since Golang is running the server and not Webpack (our use case is merely the transpilation at development time), is there way that I can get Webpack to work like this?
NOTE: our entry files are not necessarily on the same level, but have path like static/js/[relative path of one or more levels]/entry.js
Use webpack merge you can do that
Basically you will need 3 file
Main webpack.config.js file
webpack.dev.js for dev enviroment
webpack.prod.js for production enviroment
Example: webpack.dev.js
const merge = require('webpack-merge');
const baseConfig = require('./webpack.config.js');
const webpack = require("webpack");
module.exports = merge(baseConfig, {
plugins: [
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('development'),
'BASE_URL': JSON.stringify('http://localhost:5000/')
}
})
],
watch: true
});
webpack.prod.js. You can see that I'm using some optimization packge in prod mode only like OptimizeCSSAssetsPlugin, CompressionPlugin, UglifyJsPlugin to uglify and gzip the file content to improve performance. You can adjust accordingly with your need.
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CompressionPlugin = require("compression-webpack-plugin");
const merge = require('webpack-merge');
const baseConfig = require('./webpack.config.js');
const webpack = require("webpack");
module.exports = merge(baseConfig, {
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 webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production'),
'BASE_URL': JSON.stringify('a/')
}
}),
new CompressionPlugin({
test: /\.(js|css)/
}),
new UglifyJsPlugin(),
]
});
To run it simply use these 2 command in your package.json
"prod": "webpack -p --mode=production --config webpack.prod.js",
"start": "webpack --mode=development --config webpack.dev.js",

Vue CLI 3 sass-resources-loader - Options.loaders undefined

I was able to successfully configure a new Vue project using the 3.0 version of the CLI to use sass-resource-loader a few weeks ago using the information posted here: Using sass-resources-loader with vue-cli v3.x
However, after updating everything today I'm encountering the following error when running npm run serve:
TypeError: Cannot read property 'scss' of undefined
the only options that seem to be getting passed into .tap(options) are:
{ compilerOptions: { preserveWhitespace: false } }
I don't currently know enough about chainWebpack to effectively debug, but I'm working on it. If anyone has any insights into what's changed to cause this error, it'd be greatly appreciated.
my vue.config.js:
const path = require('path')
module.exports = {
chainWebpack: (config) => {
config
.module
.rule('vue')
.use('vue-loader')
.tap((options) => {
console.log(options)
options.loaders.scss = options.loaders.scss.concat({
loader: 'sass-resources-loader',
options: {
resources: [
path.resolve('./src/scss/_variables.scss'),
path.resolve('./src/scss/_mixins.scss')
]
},
})
return options
})
config
.module
.rule('scss')
.use('sass-resources-loader')
.loader('sass-resources-loader')
.options({
resources: [
path.resolve('./src/scss/_variables.scss'),
path.resolve('./src/scss/_mixins.scss')
]
})
}
}
You use vue-cli#3.x, this probably means that your project uses vue-loader#15.x
Since version 15, the vue-loader does not need additional configs for loaders.
You can configure only your main webpack loaders.
const path = require('path')
module.exports = {
chainWebpack: (config) => {
config
.module
.rule('scss')
.use('sass-resources-loader')
.loader('sass-resources-loader')
.options({
resources: [
path.resolve('./src/scss/_variables.scss'),
path.resolve('./src/scss/_mixins.scss')
]
})
}
}
You can also inspect webpack configs using the vue inspect or ./node_modules/.bin/vue-cli-service inspect commands.

Systemjs-Builder - Cannot configure properly - Bundling Typescript into a package

I want to build a quick nodejs script to package a Typescript app as SystemJS modules, a lot like what Angular2 bundles look like.
I tried different configurations but I can't seem to put my finger on it, and haven't found clear enough documentation as of yet.
Note that for this "test", I am not using Gulp or Jspm at all, just systemjs-builder for the time being (and don't plan on using jspm at all either)
Here's what my "project" looks like:
---- Project's Root
-------- index.ts // export * from './modules/index' and eventually more
-------- modules
------------ index.ts // export * from './menu/index'
------------ menu
---------------- menu.component.ts // export class
---------------- menu.service.ts // export class
I want to package this under a single file, where I will have multiple SystemRegister modules that can be consumed in an app thereafter
I tried the following without success:
var Builder = require('systemjs-builder');
// optional constructor options
// sets the baseURL and loads the configuration file
var builder = new Builder('./modules');
builder.bundle('./modules/index.ts', {
/* SystemJS Configuration Here */
baseURL: './modules',
transpiler: 'typescript',
typescriptOptions: {
"module": "system",
"emitDecoratorMetadata": true,
"experimentalDecorators": true
},
defaultExtension: 'ts',
packages: {
'modules': {
defaultExtension: 'ts'
}
}
}, 'infrastructure.js')
.then(function() {
console.log('Build complete');
})
.catch(function(err) {
console.error(err);
})
First of all, the defaultExtension options doesn't seem to work at all
So when I do import {something} from 'filePath'; (without extension), it tries to load filePath, instead of filePath.ts;
Second, if I try adding the .ts extension in my imports (which I don't want to do), it complains that the code is invalid (unexpected token #, unexpected token menuItem and so forth)
Anyone have a good example or some explanations on how this is supposed to work?
Thank you
here you have an example: angular typescript skeleton
build task looks like this:
const path = require('path');
const Builder = require('jspm').Builder;
const builder = new Builder();
const packageJson = require(path.join(config.projectDir, 'package.json'));
return beginBuild()
.then(buildSFX)
.catch((err) => console.log('Build Failed', err));
function beginBuild() {
builder.reset();
return builder.loadConfig(path.join(config.projectDir, packageJson.jspm.configFile))
}
function buildSFX() {
const appName = packageJson.name;
const distFileName = `${appName}.min.js`;
const outFile = path.join(config.distDir, distFileName);
const moduleName = 'app';
const buildConfig = {
format: 'global',
minify: true,
sourceMaps: true
};
return builder.buildStatic(moduleName, outFile, buildConfig);
}
and jspm conf looks like this:
System.config({
defaultJSExtensions: true,
transpiler: "typescript",
typescriptOptions: {
"tsconfig": "src/tsconfig.json"
},
paths: {
"github:*": "vendor/jspm_packages/github/*",
"npm:*": "vendor/jspm_packages/npm/*",
"app": "src/index"
}
/// ...
}
Why do you want to bundle typescript? Bundling is a method used for optimizing the delivery of source code to the browser. The browser doesn't know typescript, it only knows javascript (unless you do on the fly transpiling).

Categories