javascriptreactjswebpackhtml-webpack-pluginmini-css-extract-plugin

Neither MiniCssExtractPlugin's linkType nor html-webpack-link-type-plugin is working


Please find my webpack config below:

const LinkTypePlugin = require('html-webpack-link-type-plugin').HtmlWebpackLinkTypePlugin;
const path = require('path');
const webpack = require('webpack');
const FileManagerPlugin = require('filemanager-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = function(env) {
    const config = {};
    config.entry = {
        'apps/xyz': './apps/xyz/index.js',
    };

    config.mode = (env && env.NODE_ENV) || 'production';

    config.output = {
        path: path.resolve(__dirname, './dist'),
        filename: './[name]/bundle.[hash].js',
    };

    if (config.mode === 'development') {
        config.devtool = 'eval-source-map';
    } else {
        config.devtool = false;
    }

    config.module = {
        rules: [
            {
                test: /\.jsx?$/,
                exclude: /[\\/]node_modules[\\/]\.+/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: [
                            [
                                '@babel/preset-env',
                                {
                                    targets: 'defaults',
                                    useBuiltIns: 'entry',
                                    corejs: 3,
                                },
                            ],
                            '@babel/preset-react',
                        ],
                        plugins: [
                            '@babel/plugin-proposal-class-properties',
                            ...(config.mode === 'production'
                                ? [['transform-react-remove-prop-types', { removeImport: true }]]
                                : []),
                        ],
                    },
                },
            },
            {
                test: /\.tsx?$/,
                use: 'ts-loader',
                exclude: /node_modules/,
            },
            // loader for processing sass templates used by react files
            {
                test: /\.(sass|scss|css)$/,
                exclude: /[\\/]node_modules[\\/]\.+/,
                use: [
                    config.mode === 'production'
                        ? {
                              loader: MiniCssExtractPlugin.loader,
                              options: { publicPath: '../' },
                          }
                        : 'style-loader',
                    'css-loader',
                    'sass-loader',
                ],
            },
            {
                test: /\.(jpe?g|png|gif|svg|bmp)$/i,
                loader: 'file-loader',
                options: {
                    name: './[path][hash].[ext]',
                    useRelativePaths: true,
                },
            },
        ],
    };

    config.resolve = {
        extensions: ['.tsx', '.ts', '.js'],
        alias: {
            src: path.resolve(__dirname),
        },
    };

    // Configure plugins
    config.plugins = [
        new CleanWebpackPlugin(),
        new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /en-gb/),
        new HtmlWebpackPlugin({
            template: path.resolve(__dirname, './apps/xyz/index.html'),
            filename: 'apps/xyz/index.html',
            chunks: ['apps/xyz'],
            minify: {
                removeStyleLinkTypeAttributes: false,
                removeScriptTypeAttributes: false,
                collapseWhitespace: true,
                removeComments: true,
                removeRedundantAttributes: true,
                useShortDoctype: true,
            },
        }),
        new MiniCssExtractPlugin({
            filename: './[name]/main.[hash].css',
            chunkFilename: './[name]/main-[id].[hash].css',
            insert: 'text/css',
            linkType: 'text/css',
        }),
        new LinkTypePlugin({
            '**/*.css': 'text/css',
        }),
        new FileManagerPlugin({
            onEnd: [
                {
                    delete: ['../extension/public'],
                    copy: [
                        {
                            source: './dist/',
                            destination: '../extension/public/',
                        },
                    ],
                },
            ],
        }),
    ];

    // Adding new version of uglifyjs plugin as required by other packages
    if (env && env.NODE_ENV === 'production') {
        config.plugins.push(new UglifyJSPlugin());
    }

    return config;
};

The index.html file generated has the CSS attached but without type=text/css which I need for strict type compatibility. Please help.


Solution

  • The issue was the glob I specified in LinkTypePlugin **/*.css is not an all-cover scenario. I changed it to ./**/*.css and it works!

    The key is to look at the generated index.html. The injected links's href or src will help in defining your glob pattern.

    In cases where the generated files' path is not very straightforward, MiniCssExtractPlugin isn't able to do much.