Webpack and multiple aurelia app

Hello !

I’m trying to use a webpack configuration for all my separate SPA (single page application) that are built using Aurelia, of course. But im confuse where to ‘scope’ the app whether in webpack.config.js or aurelia.json (I tried both). And every time I compile my SPA it does compile ALL the SPA instead of the one package is needed for this app.

Lets be clear here, the whole app/packages/*/src folder are built. But only the SPA I started is served to the browser (which is all I needed and im glad)

But the webpack does compile 19 SPA for nothing. And its takes time and resources (memory). Which result ultimately by a crash of node.js where the build ran one time too much whilst im using dev-server.

genius-spa-quality-desktop: > genius-spa-quality-desktop@13.0.0 debug C:\git\SourceCode\Genius\Web\packages\genius-spa-quality-desktop
genius-spa-quality-desktop: > webpack-dev-server --open chrome

here’s a zip file of my current config files.

1 Like

To make the question easier & require less amount of effort for others to help, can you paste the configure here/ and a screenshot of your project structure (packges folder)? It should invite & engage better :crossed_fingers:

aurelia.json:

 {
    "name": "genius-spa-job-desktop",
    "type": "project:application",
    "paths": {
        "root": "src",
        "resources": "resources",
        "elements": "resources/elements",
        "attributes": "resources/attributes",
        "valueConverters": "resources/value-converters",
        "bindingBehaviors": "resources/binding-behaviors"
    },
    "transpiler": {
        "id": "typescript",
        "fileExtension": ".ts"
    },
    "build": {
        "options": {
            "server": "dev",
            "extractCss": "prod",
            "coverage": false
        }
    },
    "platform": {
        "hmr": false,
        "open": false,
        "port": 53251,
        "host": "localhost",
        "output": "dist"
    },
    "packageManager": "npm"
}

webpack.config.js

const { AureliaPlugin, ModuleDependenciesPlugin } = require("aurelia-webpack-plugin");
    const HtmlWebpackPlugin = require("html-webpack-plugin");
    const CopyWebpackPlugin = require("copy-webpack-plugin");
    const { resolve } = require("path");
    const project = require("./aurelia_project/aurelia.json");
    const outDir = resolve(__dirname, project.platform.output);
    const path = require("path");

const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const srcDir = path.resolve(__dirname, "src");
 const title = "Genius SPA Job Desktop";
const baseUrl = "/";

const ensureArray = config => (config && (Array.isArray(config) ? config : [config])) || [];
const when = (condition, config, negativeConfig) => (condition ? ensureArray(config) : ensureArray(negativeConfig));
const cssRules = [{ loader: "css-loader", options: { importLoaders: 1 } }, { loader: "postcss-loader" }];
module.exports = function (mode) {
    return {
        mode: mode || "development",
        resolve: {
            symlinks: false,
            extensions: [".ts", ".js"],
            modules: [srcDir, "node_modules"],
        },
        entry: {
            app: ["aurelia-bootstrapper", "./src/style/spa-app.scss"],
        },
        output: {
            path: outDir,
            publicPath: baseUrl,
            filename: mode === "production" ? "[name].[chunkhash].bundle.js" : "[name].[hash].bundle.js",
            sourceMapFilename: mode === "production" ? "[name].[chunkhash].bundle.map" : "[name].[hash].bundle.map",
            chunkFilename: mode === "production" ? "[name].[chunkhash].chunk.js" : "[name].[hash].chunk.js",
        },
        devtool: mode === "production" ? "none" : "source-map",
        devServer: {
            contentBase: outDir,
            // serve index.html for all 404 (required for push-state)
            historyApiFallback: true,
            hot: project.platform.hmr,
            port: project.platform.port,
        },
        module: {
            rules: [
                { test: /[^.]*\.html/i, loader: "html-loader" },
                { test: /\.ts$/i, loader: "ts-loader", options: { happyPackMode: true, transpileOnly: true }, exclude: /node_modules/ },
                {
                    test: /\.css$/i,
                    issuer: [{ not: [{ test: /\.html$/i }] }],
                    use: ["style-loader", ...cssRules],
                },
                {
                    test: /\.css$/i,
                    issuer: [{ test: /\.html$/i }],
                    use: cssRules,
                },
                {
                    test: /\.scss$/,
                    use: [
                        "style-loader",
                        "css-loader",
                        {
                            loader: "postcss-loader",
                        },
                        {
                            loader: "sass-loader",
                            options: {
                                sassOptions: {
                                    includePaths: [path.resolve(__dirname, "../../node_modules/@syncfusion")],
                                },
                            },
                        },
                    ],
                },
            ],
        },
        optimization:
            mode !== "production" //do not generate chunks while in Dev - it prevent the debug from working
                ? {}
                : {
                      runtimeChunk: true, // separates the runtime chunk, required for long term cacheability
                      // moduleIds is the replacement for HashedModuleIdsPlugin and NamedModulesPlugin deprecated in https://github.com/webpack/webpack/releases/tag/v4.16.0
                      // changes module id's to use hashes be based on the relative path of the module, required for long term cacheability
                      moduleIds: "hashed",
                      // Use splitChunks to breakdown the App/Aurelia bundle down into smaller chunks
                      // https://webpack.js.org/plugins/split-chunks-plugin/
                      splitChunks: {
                          hidePathInfo: true, // prevents the path from being used in the filename when using maxSize
                          chunks: "all",
                          // sizes are compared against source before minification
                          maxSize: 200000, // splits chunks if bigger than 200k, adjust as required (maxSize added in webpack v4.15)
                          cacheGroups: {
                              default: false, // Disable the built-in groups default & vendors (vendors is redefined below)
                              // You can insert additional cacheGroup entries here if you want to split out specific modules
                              // This is required in order to split out vendor css from the app css when using --extractCss
                              // For example to separate font-awesome and bootstrap:
                              // fontawesome: { // separates font-awesome css from the app css (font-awesome is only css/fonts)
                              //   name: 'vendor.font-awesome',
                              //   test:  /[\\/]node_modules[\\/]font-awesome[\\/]/,
                              //   priority: 100,
                              //   enforce: true
                              // },
                              // bootstrap: { // separates bootstrap js from vendors and also bootstrap css from app css
                              //   name: 'vendor.font-awesome',
                              //   test:  /[\\/]node_modules[\\/]bootstrap[\\/]/,
                              //   priority: 90,
                              //   enforce: true
                              // },

                              // This is the HTTP/1.1 optimised cacheGroup configuration
                              vendors: {
                                  // picks up everything from node_modules as long as the sum of node modules is larger than minSize
                                  test: /[\\/]node_modules[\\/]/,
                                  name: "vendors",
                                  priority: 19,
                                  enforce: true, // causes maxInitialRequests to be ignored, minSize still respected if specified in cacheGroup
                                  minSize: 30000, // use the default minSize
                              },
                              vendorsAsync: {
                                  // vendors async chunk, remaining asynchronously used node modules as single chunk file
                                  test: /[\\/]node_modules[\\/]/,
                                  name: "vendors.async",
                                  chunks: "async",
                                  priority: 9,
                                  reuseExistingChunk: true,
                                  minSize: 10000, // use smaller minSize to avoid too much potential bundle bloat due to module duplication.
                              },
                              commonsAsync: {
                                  // commons async chunk, remaining asynchronously used modules as single chunk file
                                  name: "commons.async",
                                  minChunks: 2, // Minimum number of chunks that must share a module before splitting
                                  chunks: "async",
                                  priority: 0,
                                  reuseExistingChunk: true,
                                  minSize: 10000, // use smaller minSize to avoid too much potential bundle bloat due to module duplication.
                              },
                          },
                      },
                  },
        plugins: [
            new CleanWebpackPlugin(),
            // the AureliaPlugin translates Aurelia's conventions to something Webpack understands
            // and must be included in order for Webpack to work
            new AureliaPlugin(),
            new ModuleDependenciesPlugin({
                "aurelia-testing": ["./compile-spy", "./view-spy"],
                "aurelia-i18n": [
                    { name: "locales/en/attachments.json" },
                    { name: "locales/en/common.json" },
                    { name: "locales/en/confirm.json" },
                    { name: "locales/en/error.json" },
                    { name: "locales/en/info.json" },
                    { name: "locales/en/job-view-entity.json" },
                    { name: "locales/en/job.json" },
                    { name: "locales/en/quote.json" },
                    { name: "locales/en/ui.json" },
                    { name: "locales/en/ui.json" },
                    { name: "locales/fr/attachments.json" },
                    { name: "locales/fr/common.json" },
                    { name: "locales/fr/confirm.json" },
                    { name: "locales/fr/error.json" },
                    { name: "locales/fr/info.json" },
                    { name: "locales/fr/job-view-entity.json" },
                    { name: "locales/fr/job.json" },
                    { name: "locales/fr/ui.json" },
                ],
            }),
            new HtmlWebpackPlugin({
                template: "index.ejs",
                minify:
                    mode === "production"
                        ? {
                              removeComments: true,
                              collapseWhitespace: true,
                              collapseInlineTagWhitespace: true,
                              collapseBooleanAttributes: true,
                              removeAttributeQuotes: true,
                              minifyCSS: true,
                              minifyJS: true,
                              removeScriptTypeAttributes: false,
                              removeStyleLinkTypeAttributes: false,
                              ignoreCustomFragments: [/\${.*?}/g],
                          }
                        : false,
                metadata: {
                    // available in index.ejs //
                    title,
                    baseUrl,
                },
            }),
            new CopyWebpackPlugin({
                patterns: [
                    { from: "static/favicon.ico", to: "favicon.ico" },
                    { from: "../genius-web-shell/wwwroot", to: "resources/wwwroot" },
                    { from: "src/resources/Genius_Gear_Icon_Loading.png", to: "resources/Genius_Gear_Icon_Loading.png" },
                    { from: "src/resources/image_not_available.png", to: "resources/image_not_available.png" },
                    { from: "src/resources/logo_inverse.png", to: "resources/logo_inverse.png" },
                ],
            }),
        ],
    };
};

Thank you for suggesting it :smiley: