Problem:
After I upgraded AJV.js to Version 6.4 my vendor bundle includes the "uri-js" ESNEXT version instead the ES5 version what breaks IE11 compatibillity.
Analysis:
I figured that that AJV referes to uri-js with a require('uri-js')
call and that uri-js comes in two flavors:
/node_modules/uri-js/dist/:
For some reason Webpack (V 4.8) bundles the 'esnext' flavor of uri-js into my vendor-bundle instead using the 'es5'. I couldn't find how/where I have to specify that my preferred build target is.
Here is my webpack.config.js:
const path = require("path");
const webpack = require("webpack");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
entry: {
app: './src/index.tsx'
},
output: {
filename: "js/[name].bundle.js",
path: __dirname + "/dist"
},
devtool: "source-map",
resolve: {
extensions: [".ts", ".tsx", ".js", ".jsx", ".json"]
},
module: {
rules: [
{
test: /\.tsx?$/,
loader: "ts-loader"
},
{
test: /\.less$/,
use: ExtractTextPlugin.extract({
use: [{
loader: "css-loader",
options: {
localIdentName: '[local]--[hash:5]',
sourceMap: true
}
}, {
loader: "less-loader",
options: {
sourceMap: true
}
}],
fallback: "style-loader",
publicPath: "../"
}),
exclude: "/node_modules/"
},
{
test: /\.html$/,
use: 'raw-loader'
},
{
test: /\.jpe?g$|\.gif$|\.png$/i,
loader: "file-loader?name=assets/img/[name].[ext]"
},
{
test: /\.woff2?$|\.ttf$|\.eot$|\.svg$/,
use: "file-loader?name=assets/[name].[ext]"
}
]
},
plugins: [
new ExtractTextPlugin({
filename: "quino/style/style.css",
allChunks: true
}),
new HtmlWebpackPlugin({
template: "src/index.html",
filename: "index.html"
}),
new CopyWebpackPlugin([])
],
optimization: {
splitChunks: {
cacheGroups: {
commons: { test: /[\\/]node_modules[\\/]/, name: "vendors", chunks: "all" }
}
}
}
};
package.json:
{
"name": "MyApp",
"version": "1.0.0",
"sideEffects": false,
"description": "-",
"private": false,
"scripts": {
"build": "webpack --config webpack.config.js --mode production",
"dev": "webpack-dev-server --config webpack.config.js --host 0.0.0.0 --progress --colors --history-api-fallback --mode development"
},
"author": "Me",
"license": "some",
"devDependencies": {
.... stuff ....
},
"dependencies": {
.... stuff ....
"ajv": "^6.4.0",
.... more stuff ....
}
}
I do understand that my own code gets transpiled to ES5 using the TypeScript (V 2.8) compiler. But what about the node_modules? Especially the one that already ship a ES5 version within their dist-folder?
In case it matters here my tsconfig.json:
{
"compilerOptions": {
"outDir": "build/dist",
"module": "esnext",
"target": "es5",
"lib": ["es6", "dom"],
"sourceMap": true,
"allowJs": true,
"jsx": "react",
"moduleResolution": "node",
"rootDir": "src",
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": true,
"strictNullChecks": true,
"suppressImplicitAnyIndexErrors": true,
"noUnusedLocals": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true
},
"exclude": [
"dist/**",
"./*.js",
"node_modules",
"build",
"scripts",
"acceptance-tests",
"webpack",
"jest",
"src/setupTests.ts"
]
}
I also thought about including Babel to downgrade all node_modules to ES5 but that sounds like an overkill to me especially as the modules have included ES5 flavors already.
Questions:
Can I specify that I prefere ES5 version of the dist
folder for my node_modules
? Maybe in my webpack.config or in package.json
?
How does the selection of the right node_modules/.../dist/
folders work?
Webpack allows you to define externals - modules that should not be bundled. When bundling with Webpack for the backend - you usually don't want to bundle its node_modules dependencies. This library creates an externals function that ignores node_modules when bundling in Webpack.
Webpack builds a dependency graph used internally Now all modules that are used in your app are included in the dependency graph. Your project have many installed dependencies in the node_modules folder that should not be included in your client-side JavaScript production bundle.
You can bundle your JavaScript using the CLI command by providing an entry file and output path. Webpack will automatically resolve all dependencies from import and require and bundle them into a single output together with your app's script.
webpack.config.js exports = { target: 'node', }; In the example above, using node webpack will compile for usage in a Node. js-like environment (uses Node. js require to load chunks and not touch any built in modules like fs or path ).
- Can I specify that I prefere ES5 version of the dist folder for my node_modules? Maybe in my webpack.config or in package.json?
As I understand there is no common way for handling different flavor (eg. ES5, ESNEXT, etc.) of the same NPM package. Each package has its own way of doing things. So there is no general way of choosing things. Instead one have to incorporate stuff into your task-runner (Gulp, Webpack, Grunt, etc) to address problems arise.
- How does the selection of the right node_modules/.../dist/ folders work?
A NPM package contains a package.json
. Within this file there is a main
field which specifies what to include/use in your app or what gets picked by the bundler etc. If no main
value exists index.js
will be used as the default.
The rest of the selection process is package-specific. This applies also to the folder structure of a package. Some use /dist/..
for different flavors others ship debug and production version in other folders. Highly depends on each package itself what files/versions of files are used.
There is no standardized system like in .net Nuget packages the structure of the lib/...
folder.
What I am still not sure about is why ESNEXT version of URL-JS gets picked as the URL-JS points to its ES5 version. Working on this one ;-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With