Including webpack helper methods and polyfills only in main bundle - javascript

I'm using webpack to bundle React but I still need to transpile our legacy code base written in plain javascript. I've gotten it to work so far but I noticed that since webpack treats every javascript file as an individual bundle it is also injecting its helper methods and polyfills in every file. It would be best if those were only included in the main javascript file and that way reducing the size of the subsequent files.
Is there a way to achieve this?
If anyone's curious how I'm transpiling each legacy js file individually.
glob.sync(PATH).forEach((file) => {
exports.push({
entry: file,
output: {
path: path.resolve(__dirname),
filename: file,
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
}]
},
devtool: 'eval',
});
});

I found a way so here's how my set up is currenlty looking.
.babelrc "useBuiltIns": "entry" makes it so you polyfills (and helper methods too?) are only inserted when requested. In other words when you call "import" at the top of the file. This allows me to create a polyfill.js file with nothing in it other than import "core-js"; which turns into a much larger file with all the polyfills I need.
{
"presets": [
[
"#babel/preset-env",
{
"corejs": "3.6.4",
"useBuiltIns": "entry",
"targets": {
"ie": "11"
}
}
],
"#babel/preset-react"
],
"plugins": [
"#babel/plugin-proposal-class-properties",
"#babel/transform-runtime"
],
"sourceType": "unambiguous"
}
the webpack configuration for these files looks like (the exports collection is ultimately assigned to module.exports).
glob
.sync(PATH)
.forEach((file) => {
let config = {
entry: file,
output: {
path: path.resolve(__dirname),
filename: file,
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
}],
}
};
exports.push(config)
});
needless to say polyfill.js is the first script called in my html.

Related

Why is my webpack babel setup emitting ESM requires when I have configured my preset to commonjs?

Today I observed babel/babel-loader exhibiting some undesirable behavior. I am bundling some assets for usage on nodejs. Post-compile, a bundle is generated with references to #babel/runtime/**/esm/**. Of course, node cannot import such files, and on node bundle.js I get:
Must use import to load ES Module: /my/project/node_modules/#babel/runtime/helpers/esm/defineProperty.js
require() of ES modules is not supported.
Right. Makes sense. But babel-loader injected those imports. In fact, the parent folder in #babel/runtime has all of the non-ESM things, which I actually probably do want imported! My babel config looks as such:
{
presets: [
[
"#babel/preset-env",
{
modules: 'commonjs',
targets: {
node: "current",
esmodules: false,
},
},
],
"#babel/preset-typescript",
]
}
As you can see, I'm attempting to tell babel via targets.esmodules: false and modules: 'commonjs' to use commonjs. I hoped these entries would tell babel to not expect ESM compatibility! None the less, generated bundles still look like:
...
var _toConsumableArray2 = _interopRequireDefault(__webpack_require__(/*! #babel/runtime/helpers/esm/toConsumableArray */ "#babel/runtime/helpers/esm/toConsumableArray"));
My full webpack config is pretty terse as well:
{
entry: serverFilename,
mode: 'development',
output: {
path: path.dirname(serverBuildFilename),
filename: path.basename(serverBuildFilename)
},
target: "node",
externals: [webpackNodeExternals()],
optimization: {
moduleIds: 'named',
minimize: false
},
resolve: {
extensions: ['.ts', '.tsx', '.wasm', '.mjs', '.js', '.json'],
},
module: {
rules: [
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: babelConfig.presets // see babel config above
}
}
},
],
},
}
I can't tell if I'm missing configuration, if babel isn't respecting my configuration, or <your ideas here>!
All tips appreciated. Thanks!
It took me a while to figure out the solution and this post helps
https://github.com/webpack/webpack/issues/11696
Copied my solution from the issue here:
I ended up using webpack-node-externals in webpack config to sort of bypass this issue
const nodeExternals = require('webpack-node-externals');
// add these to the webpack config.
externals: [
nodeExternals({
whitelist: [/^#babel\/runtime/],
}),
],
This solution creates duplicated babel/runtime file injections and can also be mitigated by https://webpack.js.org/loaders/babel-loader/#babel-is-injecting-helpers-into-each-file-and-bloating-my-code

ThreeJS module is not transpiled by Babel

Im using Three.js as a module, transpiling a code using Babel, packing with WebPack. The problem is that even all the other code is properly transpiled, the three.js module is not and still contains ES6 syntax. Which causes problems in IE11.
.babelrc
{
"presets": [
[
"#babel/preset-env" , {
"targets": {
"ie": "11"
}
}]
],
"plugins": [
"#babel/plugin-proposal-class-properties",
"#babel/plugin-transform-classes"
]
}
webpack.config
module: {
rules: [
{
test: /\.js$/,
//exclude: /node_modules/,
loaders: ['babel-loader']
},
...
Here I commented out to exclude the node_module folder, but even with that the problem still persists
Any idea what is wrong and how I could get transpiled Threejs module? Thanks a lot
This worked for me:
In the webpack config, set the exclude property like this:
exclude: /node_modules\/(?!(three)\/).*/,.
This forces babel to transpile three no matter what.
Reference: stackoverflow
Cheers

BabelJS is processing the wrong files when working with Webpack 4

I started from a configuration consisting of both webpack 3 and a similarly old babel version. It can be found in the following repo:
https://github.com/konradmi/react-loadable-ssr-code-splitting
I updated both webpack and babel to their latest versions, as well as all the node modules, and migrated the old configuration accordingly. This issue could stem from any of these.
Once I finished migrating, I noticed all the babel plugins traverse my webpack configs files (which are in a separate nested folder) instead of the actual js source files which are properly processed by webpack. (I verified it by doing some logging inside of the babel plugins).
The result is the same regardless of whether I'm using .babelrc or not.
The webpack config files used to be at the root of the project as you can see in the repo I linked to above, and now they are inside of a nested "config" folder.
At first I thought it might be the cause of this issue, so I tried the following:
Using path.resolve() in the entry point in order to use an absolute path to make sure it wouldn't possibly be re-interpreted by babel from a string relative to who knows where.
Putting the webpack config files back in the root of the project and building from that path.
In all the variations I've tried - webpack always does its job perfectly, while babel is traversing the wrong files. I'm not even sure how it's possible, babel-loader should be traversing the files which it got from the previous webpack rule, which emitted the correct files.
Here's my current Webpack 4 config files concatenated into 1 file and stripped of irrelevant rules and plugins for your convenience:
const webpack = require('webpack')
const path = require('path')
const webpackNodeExternals = require('webpack-node-externals')
module.exports = {
name: 'server',
target: 'node',
externals: [webpackNodeExternals()],
entry: './src/server.tsx',
output: {
filename: 'bundle.js',
chunkFilename: '[name].js',
path: path.resolve(__dirname, '../build')
},
mode: 'development',
stats: 'verbose',
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx']
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
babelrc: false,
presets: [
[
'#babel/env',
{
'targets': {
'browsers': ['last 2 versions']
},
'debug': false
}
],
'#babel/preset-react'
],
plugins: [
'#babel/plugin-syntax-dynamic-import',
'#babel/plugin-proposal-class-properties',
'#babel/plugin-transform-object-assign',
'react-loadable/babel'
]
}
}
]
},
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: [
{
loader: 'ts-loader'
}
]
}
]
}
}
I was importing webpack in my server source code, the files babel was going over were webpack imports which I added there in the source code. It couldn't find anything else other than those imports because due to previous rules webpack was exporting a bundle with evals containing the processed code (dev mode settings). The babel plugin wasn't looking for eval statements, so the only thing I could see was the processing of webpack related imports.

Using Webpack custom loader in loaders array

I am trying to build a Webpack custom loader:
module.exports = function(source) {
// Transform the source and return it
console.log('$$$$$$$$$$$$$$$$$$$$$');
return source;
};
Now, I want to use it in my loaders array, something like:
loaders: [
{test: /\.vm$/, loader: 'vm-loader', exclude: [/node_modules/, /dist/]}
]
I tried to use resolveLoader's alias, but it did not work:
resolveLoader: {
alias: {
"vm-loader": path.join(__dirname, "./lib/velocity-plugin")
},
root: [
path.join(__dirname, 'node_modules'),
path.resolve('./node_modules')
]
}
What Am I missing?
Answering my own question:
As it turned out, my custom loader doesn't work because webpack does not work on files which where not required. In my case those html/vm files are not required and not part of the bundle (they are rendered by the server).
My solution was adding gulp in order to have this working. Another (hacky) solution will be using this method

webpack loaders and include

I'm new to webpack and I'm trying to understand loaders as well as its properties such as test, loader, include etc.
Here is a sample snippet of webpack.config.js that I found in google.
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel-loader',
include: [
path.resolve(__dirname, 'index.js'),
path.resolve(__dirname, 'config.js'),
path.resolve(__dirname, 'lib'),
path.resolve(__dirname, 'app'),
path.resolve(__dirname, 'src')
],
exclude: [
path.resolve(__dirname, 'test', 'test.build.js')
],
cacheDirectory: true,
query: {
presets: ['es2015']
}
},
]
}
Am I right that test: /.js$/ will be used only for files with extension .js?
The loader: 'babel-loader', is the loader we install using npm
The include: I have many questions on this. Am I right that anything we put inside the array will be transpiled? That means, index.js, config.js, and all *.js files in lib, app and src will be transpiled.
More questions on the include: When files get transpiled, do the *.js files get concatenated into one big file?
I think exclude is self explanatory. It will not get transpiled.
What does query: { presets: ['es2015'] } do?
In webpack config there are multiple things for configuration, important ones are
entry - can be an array or an object defining the entry point for the asset you want to bundle, can be a js as test here says do it only for /.js$. Your application if has multiple entry points use an array.
include - defines the set of path or files where the imported files will be transformed by the loader.
exclude is self explanatory (do not transform file from these places).
output - the final bundle you want to create. if you specify for example
output: {
filename: "[name].bundle.js",
vendor: "react"
}
Then your application js files will be bundled as main.bundle.js and react in a vendor.js files. It is an error if you do not use both in html page.
Hope it helped
This documentation helped me understand better. Looks like it is for webpack 1 but still applies.
https://webpack.github.io/docs/configuration.html#module-loaders
Loaders
An array of automatically applied loaders.
Each item can have these properties:
test: A condition that must be met
exclude: A condition that must not be met
include: An array of paths or files where the imported files will be transformed by the loader
loader: A string of “!” separated loaders
loaders: An array of loaders as string
This example helped me understand what is going on. Looks like you use either include or exclude but not both. The test is a condition applied to all files. So if you include a folder, each file must pass the test condition. I have not verified this, but based on the example provided by the documentation, it look like that is how it works.
module: {
rules: [
{
// "test" is commonly used to match the file extension
test: /\.jsx$/,
// "include" is commonly used to match the directories
include: [
path.resolve(__dirname, "app/src"),
path.resolve(__dirname, "app/test")
],
// "exclude" should be used to exclude exceptions
// try to prefer "include" when possible
// the "loader"
loader: "babel-loader" // or "babel" because webpack adds the '-loader' automatically
}
]
}
1) Correct.
2) Correct.
3) Correct.
4) I am unsure. My webpack.config.js file includes an output key, and does bundle it all into one file:
output: {
path: path.resolve(__dirname, 'build'),
filename: 'bundle.js'
}
5) Correct.
6) This tells babel-loader what sort of transpile you want it to perform, as well as other compile options. So, for example, if you want it to transpile jsx as well + cache results for improve performance, you would change it to:
query: {
presets: ['react', 'es2015'],
cacheDirectory: true
}

Categories

Resources