I migrated to Webpack 4 and set up everything according to the Docs, however, my vendors.js chunk is not getting compiled like the main.js chunk.
I have placed the vendors into the optimization.splitChunks.cacheGroups object, as the docs suggested, but didnt find a way to make these "cacheGroups" get compiled with babel.
My problem is that one of the libraries has a ES6 class and now IE11 isnt working due to this fact.
My webpack optimization object looks like:
optimization: {
splitChunks: {
cacheGroups: {
styles: {
name: 'styles',
test: /\.css$/,
chunks: 'all',
enforce: true
},
vendor: {
name: 'vendor',
test: /[\\/]node_modules[\\/]/,
chunks: 'all',
enforce: true
}
}
}
}
Is there a way to force webpack to compile vendors with babel as well?
Regards
you should have posted the entire webpack config to give people more context.
Anyways, optimization step has very little to do with the actual transpiling. Your vendor chunk is set to only include stuff from node_modules which is almost never processed (unless you specifically tell babel-loader to include a certain package).
Since I do not know how you configured your babel-loader I would suggest something along these lines:
{
test: /\.js$/,
exclude: (file) => {
return /node_modules/.test(file) && !file.includes("/node_modules/my-es6-module/");
}
}
The idea is to exclude all files containing node_modules unless the file path contains the name of your specific module which you do need to process with babel.
In general, having an ES6 code published to npm is a very bad practice and should be avoided at all costs.
If this is not enough, please do update your question with your webpack config to give us more insight into your setup.
Related
After running my code through webpack it contians arrow functions. I need the code to work in ie11 so I need to get rid of the arrow functions.
I'm using babel-loader for all .js files.
I wrote a loader to check code for arrow functions and ran it after the babel-loader and didn't get any arrow functions, so I know the output from babel is good.
I've also tried babel-polyfill and the babel plugin for transforming arrow funtions.
As I know the babel-loader outputs good code I suspect it might be a plugin, but I can't just disable them to test as that breaks the build.
Webpack plugins used in dev:
plugins: [
new webpack.DefinePlugin({
'process.env': require('../config/dev.env')
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
new webpack.NoEmitOnErrorsPlugin(),
// https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true
}),
// copy custom static assets
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.dev.assetsSubDirectory,
ignore: ['.*']
}
])
]
The problem also appears in prod as well, but fixing it in dev should tell me how to fix it in prod as well.
I don't know of anywhere else the arrow function could be coming from, so I expect to, in essence, get code that works on ie11, but there's arrow functions coming from somewhere so it doesn't work.
It's not my code, so I can't just post it all. I can, however, post relevant snippets, but I don't know where the problem is so I don't know what's relevant yet.
I had the same problem and found the cause and solution.
Cause
babel-loader converts the grammar of es6 and higher to es5. However, because the conversion is done by the loader, the conversion occurs only in each file before it is bundled.
After the loader completes the conversion, webpack starts to bundle. However, webpack does not care about target version of babel-loader when it bundles files. It just bundles file with grammar of it's default ECMA version(which could be es6 or later). It was the reason why bundled result includes es6 grammar such as arrow function.
Initial Step
file1 (es6)
file2 (es6)
file3 (es6)
After loader works
file1' (es5)
file2' (es5)
file3' (es5)
After webpack bundles files
bundled file (es6)
Solution
You can just simply add target: "es5" in webpack.config.js to handle this. After that, webpack bundles file in grammar of es5
// .babelrc
{
"presets": ["#babel/preset-env"]
}
// webpack.config.js
module: {
...
target: "es5", // include this!!
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
}
]
}
In webpack 5:
module.exports = {
target: ['web', 'es5']
}
target is positioned at the root of the config schema and needs to know whether it targets a node or web environment
References:
https://webpack.js.org/configuration/target/
Webpack 5 "dependOn" and target: "es5" appear to be incompatible
You can use babel. Since arrow functions comes with es6 , you can use babel to convert es5. Also this link could help to Webpack not converting ES6 to ES5.
Given below webpack config is what I used for babel.
module: {
loaders: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
babelrc: false,
presets: ["#babel/preset-env", "#babel/preset-react","es2015"]
}
}
]
}
I am learning about tree-shaking with a webpack 4/React application that uses Lodash.
At first, my Lodash usage looked like this:
import * as _ from "lodash";
_.random(...
I soon learned, via the BundleAnalyzerPlugin, that the entirety of Lodash was being included in both dev and prod builds (527MB).
After googling around I realized that I needed to use a specific syntax:
import random from "lodash/random";
random(...
Now, only random and it's dependencies are correctly included in the bundle, but I'm still a little confused.
If I need to explicitly specify functions in my import statement, then what role is the tree-shaking actually playing?
The BundleAnalyzerPlugin isn't showing a difference in payload size when comparing between dev and production mode builds (it's the correct small size in both, but I thought that tree-shaking only took place with production builds?).
I was under the impression that TreeShaking would perform some sort of static code analysis to determine which parts of the code were actually being used (perhaps based on function?) and clip off the unused bits.
Why can't we always just use * in our import and rely on TreeShaking to figure out what to actually include in the bundle?
In case it helps, here is my webpack.config.js:
const path = require("path");
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
module.exports = {
entry: {
app: ["babel-polyfill", "./src/index.js"]
},
plugins: [
new BundleAnalyzerPlugin({
analyzerMode: "static",
openAnalyzer: false
})
],
devtool: "source-map",
output: {
filename: "[name].js",
path: path.resolve(__dirname, "dist"),
chunkFilename: "[name].bundle.js",
publicPath: ""
},
module: {
rules: [
{
test: /\.js$/,
loader: "babel-loader",
include: /src/,
options: {
babelrc: false,
presets: [
[
"env",
{
targets: {
browsers: ["last 2 Chrome versions"]
}
}
],
"#babel/preset-env",
"#babel/preset-react"
],
plugins: ["syntax-dynamic-import"]
}
},
{
test: /\.(ts|tsx)$/,
use: [
{
loader: require.resolve("ts-loader"),
options: {
compiler: require.resolve("typescript")
}
}
]
}
]
},
resolve: {
symlinks: false,
extensions: [".js", ".ts", ".tsx"],
alias: {
react: path.resolve("./node_modules/react")
}
}
};
I'm invoking webpack with webpack --mode=development and webpack --mode=production.
All two existing answers are wrong, webpack do treeshake import *, however that only happens when you're using a esmodule, while lodash is not. The correct solution is to use lodash-es
Edit: this answer only applies to webpack4, while webpack 5 supported a limited subset of tree shaking for commonjs, but I haven't tested it myself
Actually, it is not related to the Webpack ability to tree-shake. base on Webpack docs about tree-shaking
The new webpack 4 release expands on this capability with a way to provide hints to the compiler via the "sideEffects" package.json property to denote which files in your project are "pure" and therefore safe to prune if unused
When you set the "sideEffects: false on your package.json based on the linked docs:
All the code noted above does not contain side effects, so we can simply mark the property as false to inform webpack that it can safely prune unused exports.
If you have some files or packages which you know they are pure add them to sideEffects to prune it if unused. There are some other solutions to do tree-shaking that I proffer to read the whole article on Webpack docs.
One of the manual ways are using direct importing like below:
import get from 'lodash/get';
That Webpack understands add just get from the whole lodash package. another way is destructing importing that needs some Webpack optimization for to tree-shaking, so you should import like below:
import { get } from 'lodash';
Also, another tricky way is just to install a specific package, I mean:
yarn add lodash.get
OR
npm install --save lodash.get
Then for import just write:
import get from 'lodash.get';
Definitely, it is not tree-shaking, it is a tight mindset development, but it causes you just add what you want.
BUT
YOU DON'T DO ANYTHING OF ABOVE SOLUTIONS, you just add the whole package by writing import * as _ from "lodash"; and then use _.random or any function and expect Webpack understand you wanna the tree-shaking be happening?
Surely, the Webpack works well. you should use some configs and coding style to see the tree-shaking happens.
If you're already using Babel, the easiest method to properly tree shake lodash is to use the official babel-plugin-lodash by the lodash team.
This uses Babel to rewrite your lodash imports into a more tree-shakeable form. Doing this dropped my team's bundle size by ~32kB (compressed) with less than 5 minutes of effort.
below is a webpack config file:
module.exports = {
mode: "development",
entry: "./src/index.ts",
output: { filename: "bundle.js" },
resolve: { extensions: [".ts"] },
module: {
rules: [
{ test: /\.ts/, use: "ts-loader", exclude: /node_modules/ }
}
]
}
};
I don't understand why we need to exclude node_modules when dealing with typescript files? Below is my points:
1-Firstly, nearly all packages are written in js not in ts, it is not going to harm if we include node_modules.
2-If we are referencing a package that is written in ts, we definitely want ts code to be compiled to js code, then we have to include node_modules to make sure everything works, don't we?
1-Firstly, nearly all packages are written in js not in ts, it is not going to harm if we include node_modules.
Excluding node_modules at the transpiling stage increases performance which could otherwise get a hit.
If we are referencing a package that is written in ts, we definitely want ts code to be compiled to js code, then we have to include node_modules to make sure everything works, don't we?
Yes, and then is the key here. Excluding node_modules at the transpiling stage doesn't prevent webpack from using its content at the bundling stage.
I'm developing a react UI component and it depends on another UI component (react-widgets/lib/DropDownlist). This javascript module has resources that end with these file extensions: *.gif, *.eot, *.svg, *.woff, *.ttf.
Webpack4 is complaining that it doesn't know how to process these file types and that I might need a loader to handle these file type. One error is:
Error in .../react-widgets/dist/fonts/rw-widgets.svg?v=4.1.0
Module parse failed: ...
**You may need an appropriate loader to handle this file type.**
So I need to update my webpack.config.js file with the appropriate loaders for those file types. My config is based off of this. Side Note: A
shout out goes to Mark England who wrote this article which does a fantastic job for how to create a reusable component.
The relevant snippet is:
// Snippet from Mark's code webpack.config.js
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: "babel-loader",
exclude: /node_modules/
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
}
]
},
I know what the syntax for webpack is to define the loaders but I don't know what loaders to use. But this sample webpack config file didn't include support for these other file types.
What have I done to try and solve the problem
I generally use create-react-app so I avoid this problem altogether. :-) It, however, doesn't allow me to create react libraries for distribution (AFAIK).
First I searched on the net webpack *.gif loader. Nothing useful.
Next I searched for webpack loaders based on file type. This gave some good results that describe the loader syntax, pointed me to some loaders file-loader and how to use them, and this question on SO that helps me realize the *.svg loader might be what I need to load svg files.
{test: /\.svg$/, use: "svg-inline-loader"},
So I might be able to use svg-inline-loader for the *.svg files.
I can repeat this approach for all of the file types.
The next approach is to examine Create React App (CRA)
I primarily develop in react, and look at the CRA webpack config files (because the create-react-app appears to stay leading edge on these topic). So I can see the url-loader is used for images (based on what the node_modules/react-scripts/config/webpack.config.dev.js file is using).
Another one down...
My question
Does webpack (or another website) have a table that lists the loaders available for given file types?
For example,
know good image loaders for the following file types are:
Webpack 4
*.gif, *.jpg => url-loader
*.svg => svg-inline-loader
*.eot => ???
I realize that because webpack is more of a plugin/loader architecture that it might not be webpacks place to have this list so another website might need to have it.
When you need a loader what do you do?
If there is no central place to look for this answer, then please share how you find loaders that are needed to solve your webpack file loading problem.
It all depends on your workflow, how u want to load assets at run-time.
For eg, if u have lot of images, it might be a good idea to use a file-loader and place them directly inside the build directory.
The above approach will increase the GET calls and the bundled js file size will not be affeted
If u have less images/small size images then you can use url-loader which converts them into data-URL and put them inside your bundled js files.
The above approach will reduce the GET calls and will slightly increase the bundled js size.
If u want combination of both, then u can set a size limit and fallback loader(file-loader) on url-loader. What this will do is, the size of the dataURL will be calculated.If the size is grater than the limit, the file-loader will be used, which will place it in the build directory.
How I use them
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'file-loader',
options: {
outputPath: 'images/',
name: '[name][hash].[ext]',
},
},
],
},
{
test: /\.(svg)$/,
exclude: /fonts/, /* dont want svg fonts from fonts folder to be included */
use: [
{
loader: 'svg-url-loader',
options: {
noquotes: true,
},
},
],
},
{
test: /.(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/,
exclude: /images/, /* dont want svg images from image folder to be included */
use: [
{
loader: 'file-loader',
options: {
outputPath: 'fonts/',
name: '[name][hash].[ext]',
},
},
],
}
I have an entire legacy AngularJS 1.x application that used to run through gulp and babel. We are transitioning to the newer Angular 2+ but I'm running into an issue trying to get Webpack to actually find and compile the legacy files. I've tried following instructions which are all almost identical like this video:
https://www.youtube.com/watch?v=H_QACBSqRBE
But the webpack config simply doesn't do anything to the existing files. Is there a way to grab a WHOLE FOLDER of older components, that DO NOT have any imports or exports? I feel like entry is supposed to follow the import dependency path but that just doesn't exist for older AngularJS 1.x projects.
Errors are NOT being thrown during the build it just...doesn't transpile or polyfill.
example of what that section of the config looks like:
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
}
}
]
We did this recently. We created "dummy" entry point files to avoid having to change all of our AngularJS files to have require/import statements.
./entry-points/feature1.ts
export const importAll = (r: any): void => {
r.keys().forEach(r);
};
importAll(require.context('./app/feature1', true, /module\.js$/));
importAll(require.context('./app/feature1', true, /(^(?!.*(spec|module)\.js).*\.js)$/));
webpack.config.js
entry: {
'feature1': './entry-points/feature1.ts'
}
More detail here