RSS Git Download  Clone
Raw Blame History 8kB 313 lines
const path = require('path');
const config = require('corifeus-builder/src/utils/config').config
const webpack = require('webpack');
const { AngularWebpackPlugin } = require('@ngtools/webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin').CleanWebpackPlugin;
const minimize = process.argv.includes('--mode=production');
const mode = minimize ? 'production' : 'development';
const useStats = process.env.hasOwnProperty('WEBPACK_STATS')

const filenamePrefix = minimize ? '[id].[contenthash]' : '[name]'

let minimizer = undefined;

const top = process.cwd()
const buildDir = top + `/dist`;

let devtool;
devtool = minimize ? false : 'source-map';

const pkg = require('../../package')
// Note: 'unsafe-eval' is required for Angular JIT compiler (used during development / hybrid ngUpgrade mode).
// Once fully migrated to Angular AOT compilation, 'unsafe-eval' can be removed.
const cspPolicy = "default-src 'self'; script-src 'self' https://www.googletagmanager.com 'unsafe-inline' 'unsafe-eval'; worker-src 'self' blob:; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self' ws: wss: http://localhost:* http://127.0.0.1:* https://www.google-analytics.com https://region1.google-analytics.com; frame-src https://redis.io; object-src 'none'; base-uri 'self'; form-action 'self'"

// https://github.com/webpack-contrib/webpack-hot-middleware/tree/master/example
/*
https://stackoverflow.com/questions/44317394/webpack-dev-server-with-hot-reload-reloading-entire-page-with-css-changes

'webpack-dev-server/client?http://localhost:8080',
'webpack/hot/only-dev-server',
*/
const vendorEntry = [
    top + "/src/vendor.js"
]
const mainEntry = [
    top + (minimize ? "/src/main.js" : '/src/main-development.js')
]

const entry = {
    vendor: vendorEntry,
    main: mainEntry,
//        editor: editorEntry,
}

if (!minimize) {
    vendorEntry.push('webpack/hot/only-dev-server')
    vendorEntry.unshift('webpack-dev-server/client?http://localhost:8080/')
}

const plugins = [
    new HtmlWebpackPlugin({
        template: `${top}/src/index.html`,
        inject: 'head',
        scriptLoading: 'defer',
        chunks: ['vendor', 'main'],
        title: pkg.description,
        minify: minimize
    }),
    new MiniCssExtractPlugin({
        // Options similar to the same options in webpackOptions.output
        // both options are optional
        filename: !minimize ? '[name].css' : '[id].[contenthash].css',
        chunkFilename: !minimize ? '[name].css' : '[id].[contenthash].css',
    }),

];

if (useStats) {
    const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
    plugins.push(
        new BundleAnalyzerPlugin()
    )
}

if (minimize) {

    plugins.unshift(
        new CleanWebpackPlugin()
    )

    devtool = false;
    const bannerText = require('corifeus-builder').utils.license();

    const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

    minimizer = [
        new CssMinimizerPlugin(),
        new TerserPlugin({
            parallel: true,
            extractComments: {
                condition: /^\**!|@preserve|@license|@cc_on/,

                filename: function (fileOptions) {
                    return `${fileOptions.filename}.LICENSE.txt`;
                },
                banner: function (webpackBanner) {
                    return `
${bannerText}
For more information about all licenses, please see ${webpackBanner}
`;
                }
            },
            terserOptions: {
                compress: {
                    warnings: false
                },
                ecma: config.ecma,
                // todo found out if mangle use or not
                // mangle: false === keep function names
                // mangle: true === drop function names
                // for mangle true we are using angularjs-annotate with babel
                mangle: true,
            },
        }),
    ]


    plugins.push(
        new webpack.BannerPlugin({
            banner: bannerText,
            include: /\.css$/,
            exclude: /\.ts$|\.js$/,

// hash:[hash], chunkhash:[chunkhash], name:[name], filebase:[filebase], query:[query], file:[file]
        })
    )

    /*
    https://webpack.js.org/guides/build-performance/#source-maps
    plugins.push(
        new webpack.SourceMapDevToolPlugin({
            filename: 'sourcemaps/[file].map',
            append: '\n//# sourceMappingURL=./[url]'
        })
    )
     */




}

// Inject API port for test/dev override (P3XR_API_PORT env var)
plugins.push(
    new webpack.DefinePlugin({
        P3XR_API_PORT: JSON.stringify(parseInt(process.env.P3XR_API_PORT || '7843')),
    })
)

// Angular AOT compilation — eliminates @angular/compiler from the bundle (~1MB savings)
plugins.push(
    new AngularWebpackPlugin({
        tsconfig: path.resolve(__dirname, '../../tsconfig.json'),
        jitMode: false,
    })
)

const rules = [
    {
        test: /\.[cm]?js$/,
        include: /node_modules/,
        resolve: { fullySpecified: false },
        use: {
            loader: 'babel-loader',
            options: {
                compact: false,
                plugins: [
                    '@angular/compiler-cli/linker/babel',
                ],
            },
        },
    },
    {
        test: /\.[jt]sx?$/,
        exclude: [/node_modules/, /src\/react/],
        loader: '@ngtools/webpack',
    },
    {
        test: /\.(scss|css)$/,
//      exclude: [`${cwd}/src/assets/ngivr.scss`],
        use: [
            {
                loader: MiniCssExtractPlugin.loader,
                options: {
                },
            },
            'css-loader',
            'sass-loader',
        ],
    },
    {
        test: /\.html$/i,
        use: [{
            loader: 'html-loader',
            options: {
                minimize: minimize,
                esModule: false,
            },
        }]
    },
    {
        test: /\.(png|jpe?g|gif|ico)$/,
        type: 'asset/resource',
    },
    {
        test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
        type: 'asset/resource',
    }, {
        test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
        type: 'asset/resource',
    }, {
        test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
        type: 'asset/resource',
    }, {
        test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
        type: 'asset/resource',
    }, {
        test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
        type: 'asset/resource',
    },
]

let optimization = {
    minimize: minimize,
    minimizer: minimizer,
}

if (minimize) {

} else {

    optimization = Object.assign(optimization, {
        runtimeChunk: 'single',
        splitChunks: {
            cacheGroups: {
                vendor: {
                    test: /[\\/]node_modules[\\/]/,
                    name: 'vendor-modules',
                    chunks: 'all',
                },
            },
        },
    })
}

const webpackConfig = {
//    watch: true,
    devtool: devtool,

    entry: entry,
    output: {
        path: buildDir,
        filename: `${filenamePrefix}.js`,
        // chunkFilename: `${filenamePrefix}.js`,
//        publicPath: '{{ app.url_subdir }}/webpack/',
        publicPath: `/ng/`,
        assetModuleFilename: 'assets/[hash][ext]',
    },
    resolve: {
        extensions: ['.ts', '.js'],
    },
    module: {
        rules: rules
    },
    optimization: optimization,
    plugins: plugins,
    mode: mode,

    devServer: {
        headers: {
            'Content-Security-Policy': cspPolicy,
        },
        static: {
            directory: './src/public',
            staticOptions: {},
            publicPath: "/ng/",
            serveIndex: true,
            watch: true,
        },
        host: '0.0.0.0',
        historyApiFallback: {
            rewrites: [
                {from: /^\/ng\/.*/, to: '/ng/index.html'},
                {from: /.*/, to: '/ng/index.html'},
            ]
        },
        setupMiddlewares: (middlewares, devServer) => {
            devServer.app.get('/', (req, res) => res.redirect('/ng/'));
            return middlewares;
        },
        // hotOnly: true,
        client: {
            overlay: false,
        },
    },

}

webpackConfig.ignoreWarnings = [/Failed to parse source map/];

// Ignore the React/MUI port directory to prevent hot-reload loops when Vite is running
webpackConfig.watchOptions = {
    ignored: [
        '**/src/react/**',
        path.resolve(top, 'dist-react') + '/**',
    ],
};

module.exports = webpackConfig