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" },
],
}),
],
};
};