Webpack 4 - Bundler Issue - Dependency Graph Includes Entire Static Directory

Viewed 20

We might be the only ones doing this, but we version our js files by adding a version # at the end of them, so in a single directory you can see:

item_22.3.js
item_22.4.js
...
itemhub_22.3.js
itemhub_22.4.js
..
itemiweditor_22.3.js
itemiweditor_22.4.js
...
etc

Both versions of each script file contains the same class name and the class name never changes.

export default class Item {}
export default class ItemHub {}
export default class IWItemEditor {}

We do eventually delete old versions when they are no longer on production, but my main issue is when this code is bundled. In the webpack.config.js we use over 20 entry points, but for this example I will only use one since the issue still remains.

ex: itemhub: ['babel-polyfill', "./scripts/default/item/itemhub_22.4.js"]

When specifying the itemhub entry point I was expecting the webpack to go to itemhub_22.4.js and create a depenency graph based on the import/require in the script file, but it seems that it is instead bundling the entire directory into a single itemhub.min.js file.

I'm using BundleAnalyzerPlugin to see that itemhub.min.js doesn't look right.

BundleAnalyzerPlugin Results

I made sure that all of the import/require code does NOT reference older script versions, so I'm not sure why the entire directory is being included in the bundled code.

Any help with this would be greatly appreciated!

webpack.config.js

/// <binding />
//https://webpack.js.org/guides/getting-started/
const path = require("path"),
    version = "22.4",
    webpack = require("webpack"),
    //WebpackStrip = require("webpack-strip"),
    TerserPlugin = require('terser-webpack-plugin'),
    MiniCssExtractPlugin = require("mini-css-extract-plugin"),
    { CleanWebpackPlugin } = require('clean-webpack-plugin'),
    BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = env => {
    const nodeEnv = env && env.prod === 'true' ? 'production' : 'development',
        isProd = nodeEnv === 'production';
    return {
        mode: nodeEnv,
        devtool: isProd ? false : "source-map", //https://github.com/babel/babel/issues/7935
        target: "web",
        watch: false,
        context: path.resolve(__dirname, "content/layout"),
        entry: {
            itemhub: ['babel-polyfill', "./scripts/default/item/itemhub_22.4.js"]
        },
        output: {
            path: path.resolve(__dirname, `content/layout/bundles/js/${version}`),
            filename: `[name].min.js`,
            chunkFilename: `[name].chunk.js`, // lazy loading files
            crossOriginLoading: "anonymous",
            publicPath: "/bundles/",
            libraryTarget: 'var',
            library: '_iw[name]'
        },
        externals: {
            ItemEnterOptions: 'ItemEnterOptions'
        },
        optimization: isProd ? {
            minimize: true,
            minimizer: [new TerserPlugin({
                extractComments: 'all'
                //test: /\.js(\?.*)?$/i,
                //exclude: /\/excludes/,
                //parallel: true
            })],
            splitChunks: {
                cacheGroups: {
                    vendor: {
                        name: "node_vendors",
                        test: /[\\/]node_modules[\\/]/,
                        chunks: "all",
                        priority: -10
                    },
                    default: {
                        minChunks: 2,
                        priority: -20,
                        reuseExistingChunk: true
                    }
                }
            }
        } : {
                splitChunks: {
                    cacheGroups: {
                        vendors: {
                            name: "node_vendors",
                            test: /[\\/]node_modules[\\/]/,
                            chunks: "all",
                            priority: -10
                        },
                        default: {
                            minChunks: 2,
                            priority: -20,
                            reuseExistingChunk: true
                        }
                    }
                }
        },
        node: {
            fs: "empty"
        },
        devServer: {
            contentBase: "./content/bundles"
        },
        module: {
            noParse: [/\.min\.js$/, /\.bundle\.js$/],
            rules: [
                {
                    test: /[/\.js$,\.es6$/]/, // regex for file extension for babel to process
                    exclude: /(plugins|node_modules)/,
                    use: {
                        loader: 'babel-loader',
                        options: {
                            presets: ['@babel/preset-env'],
                            plugins: [
                                /*"@babel/plugin-transform-runtime", --breaks jqxwidgets */
                                "@babel/plugin-syntax-dynamic-import",
                                "@babel/plugin-transform-arrow-functions",
                                "@babel/plugin-transform-template-literals",
                                '@babel/plugin-proposal-class-properties'

                            ],
                            cacheDirectory: true
                        }
                    }
                }, {
                    test: /\.s?css$/,
                    use: [
                        MiniCssExtractPlugin.loader,
                        "css-loader"
                    ]
                }, {
                    test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
                    exclude: /node_modules/,
                    use: [
                        {
                            loader: 'url-loader',
                            options: {
                                limit: 0, // base64 the image instead of referencing an external url
                                publicPath: "../images",
                                outputPath: "../images",
                                name: '[name].[ext]'
                            }
                        },
                    ]
                }
            ]
        },
        resolve: {
            extensions: [".js", ".es6", ".css"], // by default webpack loads the js extension so we are overriding for our es6 extensions so we can do require('file') and not need an extension
            modules: [
                path.resolve(__dirname, 'content/layout/scripts/default'),
                path.resolve(__dirname, 'content/layout/styles/default'),
                path.resolve(__dirname, 'content/layout/graphics/default'),
                'node_modules'
            ]
        },
        plugins: [
            new CleanWebpackPlugin(), // clear out all the old junk
            new MiniCssExtractPlugin({
                filename: `../../css/${version}/[name].css`,
                chunkFilename: "[id].min.css"
            }),
            new webpack.ProvidePlugin({
                diff_match_patch: 'diff-match-patch',
                DIFF_EQUAL: ['diff-match-patch', 'DIFF_EQUAL'],
                DIFF_INSERT: ['diff-match-patch', 'DIFF_INSERT'],
                DIFF_DELETE: ['diff-match-patch', 'DIFF_DELETE'],
            }),
            new BundleAnalyzerPlugin()
        ]
    }
};

package.json

{
  "name": "iwstatic",
  "version": "22.4.0",
  "description": "Static content for Item Workshop",
  "main": "login.js",
  "scripts": {
    "refreshVSToken": "vsts-npm-auth -config .npmrc",
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack-dev-server",
    "//": "start script allows npm start to load up dev webserver",
    "buildproduction": "webpack --env.prod=true --optimize-minimize --progress",
    "build": "webpack --env.prod=false",
    "lint": "eslint content/layout/scripts/default/login/ content/layout/scripts/default/home/",
    "lintfix": "eslint content/layout/scripts/default/login/ content/layout/scripts/default/home/ --fix",
    "watch": "npm-watch"
  },
  "repository": {
    "type": "git",
    "url": "https://itsdevelopment@dev.azure.com/itsdevelopment/Item%20Workshop/_git/2-website-static"
  },
  "author": "Johaness Noreiga",
  "license": "ISC",
  "eslintConfig": {
    "parser": "babel-eslint",
    "plugins": [
      "babel"
    ],
    "rules": {
      "babel/new-cap": 0,
      "babel/camelcase": 0,
      "babel/no-invalid-this": 0,
      "babel/object-curly-spacing": 1,
      "babel/quotes": 1,
      "babel/semi": 1,
      "babel/no-unused-expressions": 1,
      "babel/valid-typeof": 1
    },
    "env": {
      "browser": true,
      "node": false,
      "targets": {
        "browsers": [
          "last 2 versions",
          "ie >= 9"
        ]
      }
    },
    "parserOptions": {
      "ecmaVersion": 6,
      "sourceType": "module",
      "ecmaFeatures": {
        "jsx": true
      }
    }
  },
  "eslintIgnore": [
    "/Content/js/release",
    "/node_modules"
  ],
  "devDependencies": {
    "@babel/core": "^7.9.0",
    "@babel/plugin-proposal-class-properties": "^7.8.3",
    "@babel/plugin-syntax-dynamic-import": "^7.8.3",
    "@babel/plugin-transform-runtime": "^7.9.0",
    "@babel/preset-env": "^7.9.5",
    "@babel/register": "^7.9.0",
    "@babel/runtime": "^7.9.2",
    "@webpack-cli/serve": "^1.6.1",
    "ajax-request": "^1.2.3",
    "babel-core": "^7.0.0-0",
    "babel-loader": "^7.1.5",
    "babel-polyfill": "^6.26.0",
    "babel-preset-env": "^1.7.0",
    "clean-webpack-plugin": "^3.0.0",
    "codemirror": "^5.52.2",
    "cssimportant-loader": "^0.4.0",
    "diff-match-patch": "^1.0.4",
    "diff_match_patch": "^0.1.1",
    "eslint-plugin-babel": "^5.3.0",
    "extract-loader": "^3.1.0",
    "extract-text-webpack-plugin": "^4.0.0-beta.0",
    "file-loader": "^3.0.1",
    "file-system": "^2.2.2",
    "foreach": "^2.0.5",
    "html-loader": "^0.5.5",
    "jquery": "^1.8.3",
    "jquery-ui": "^1.12.1",
    "json-diff": "^0.5.4",
    "ladda": "^2.0.1",
    "mini-css-extract-plugin": "^0.6.0",
    "mutationobserver-polyfill": "^1.3.0",
    "promise-polyfill": "8.1.0",
    "supplant": "^0.2.0",
    "uglifyjs-webpack-plugin": "^2.2.0",
    "url-loader": "^1.1.2",
    "webpack": "^4.42.1",
    "webpack-bundle-analyzer": "^4.6.1",
    "webpack-cli": "^3.3.11",
    "webpack-strip": "^0.1.0"
  },
  "dependencies": {
    "audio.js": "^1.1.3",
    "autocompleter": "^6.1.0",
    "babel-eslint": "^10.1.0",
    "babel-plugin-transform-remove-console": "^6.9.4",
    "babel-preset-es2015": "^6.24.1",
    "css-loader": "^2.1.1",
    "jquery.quicksearch": "^2.4.0",
    "json-beautify": "^1.1.1",
    "npm-watch": "^0.11.0",
    "path": "^0.12.7",
    "style-loader": "^0.23.1",
    "tippy.js": "^5.2.1",
    "video.js": "^7.18.1",
    "webpack-dev-server": "^4.8.1"
  },
  "-vs-binding": {
    "BeforeBuild": [
      "build"
    ],
    "AfterBuild": [
      "buildproduction"
    ]
  },
  "watch": {
    "build": "scripts/**/*.js"
  }
}

itemhub_22.4.js

import ItemCore from "item/itemcore_21.5.js";

const itemjs = "./item_22.4.js";
const itemaccessibilityjs = "./itemaccessibility_21.5.js";
const itemeditorjs = "./itemeditor_22.4.js";
const itemrationalesjs = "./itemrationales_22.4.js";
const itemexhibitsjs = "./itemexhibits_21.5.js";

export default class ItemHub {
...
...

                switch ($(ui.tab).prop("id").toLowerCase()) {
                    case "itemhub_itemtab":
                        (async () => {
                            await import(itemjs)
                                .then((module) => {
                                    new module.default().Initialize();
                                });
                        })();
                        break;
                    case "itemhub_accessibilitytab":
                        (async () => {
                            await import(itemaccessibilityjs)
                                .then((module) => {
                                    new module.default().Initialize();
                                });
                        })();
                        break;
                    case "itemhub_rationalestab":
                        (async () => {
                            await import(itemrationalesjs)
                                .then((module) => {
                                    new module.default().Initialize();
                                });
                        })();
                        break;
                    case "itemhub_propertiestab":
                        ItemPropertiesTab.Initialize();
                        break;
                    case "itemhub_exhibitstab":
                        (async () => {
                            await import(itemexhibitsjs)
                                .then((module) => {
                                    new module.default().Initialize();
                                });
                        })();
                        break;
                }
...
...
}
0 Answers
Related