Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to select node_modules dist flavor to bundled with webpack

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/:

  • es5
  • esnext

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:

  1. 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?

  2. How does the selection of the right node_modules/.../dist/ folders work?

like image 574
Marc Avatar asked May 16 '18 06:05

Marc


People also ask

Does webpack bundle node_modules?

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.

How does a webpack decide to bundle?

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.

How do you bundle on a webpack?

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.

Does webpack compile node modules?

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 ).


1 Answers

  1. 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.

  1. 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 ;-)

like image 118
Marc Avatar answered Oct 17 '22 10:10

Marc