webdeveric / webpack-assets-manifest

This webpack plugin will generate a JSON file that matches the original filename with the hashed version.
https://www.npmjs.com/package/webpack-assets-manifest
MIT License
323 stars 34 forks source link

Not added compressed files in manifest #56

Closed Serzh470 closed 3 years ago

Serzh470 commented 4 years ago

The problem

After using CompressionWebpackPlugin final chunk and entries files appeared in manifest.json without .gz extension

Technical details

After using CompressionWebpackPlugin final chunk and entries files appeared in manifest.json without .gz extension

Webpack version

"webpack": "^4.41.1", "compression-webpack-plugin": "^3.0.0", "webpack-assets-manifest": "^3.1.1",

Webpack config

const fs = require("fs");
const path = require("path");
const webpack = require("webpack");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const TerserPlugin = require("terser-webpack-plugin");
const WebpackAssetsManifest = require("webpack-assets-manifest");
const CompressionPlugin = require("compression-webpack-plugin");

/* --------------------------------------------------- BUILD MODE --------------------------------------------------- */
// Parse command-line arguments
const parsedArgs = require("minimist")(process.argv.slice(2));

// input dir
const APP_DIR = path.resolve(__dirname, "./");
// output dir
const BUILD_DIR = path.resolve(__dirname, "./dist");

const {
    mode = "development",
    devserverPort = 9000,
    portalPort = 8000,
    measure = false,
} = parsedArgs;

const isDevMode = mode !== "production";

/* ----------------------------------------------------- PLUGINS ---------------------------------------------------- */
// Define webpack plugins
const plugins = [
    // creates a manifest.json mapping of name to hashed output used in template files
    new WebpackAssetsManifest({
        publicPath: true,
        // This enables us to include all relevant files for an entry
        entrypoints: true,
        // Also write to disk when using devServer
        // instead of only keeping manifest.json in memory
        // This is required to make devServer work with Django and Flask.
        writeToDisk: isDevMode,
        // convert "js.gz" to "js" on entrypoint key in production mode
        // "js": [
        //     "entry.point.name": "entry.point.chunk.js.gz"
        // ]
        // fileExtRegex: isDevMode ? /\.\w{2,4}\.(?:map|gz)$|\.\w+$/i : /\.\w{2,4}(?=\.map|\.gz)|\.\w+$/i,
    }),

    // create fresh dist/ upon build
    new CleanWebpackPlugin(),

    // expose mode variable to other modules
    new webpack.DefinePlugin({ "process.env.WEBPACK_MODE":JSON.stringify(mode) }),
];

if (isDevMode) {
    // Enable hot module replacement
    plugins.push(new webpack.HotModuleReplacementPlugin());
} else {
    // text loading (webpack 4+)
    plugins.push(new MiniCssExtractPlugin({
        filename: "[name].[chunkhash].entry.css",
        chunkFilename: "[name].[chunkhash].chunk.css",
    }));

    // optimize css
    plugins.push(new OptimizeCSSAssetsPlugin());

    // add compressing to assets
    plugins.push(new CompressionPlugin({
        deleteOriginalAssets: true,
        exclude: "manifest.json",
    }));
}

/* ------------------------------------------------- OUTPUT JS FILES ------------------------------------------------ */

// define files path and names
const output = {
    path: BUILD_DIR,
    publicPath: "/static/assets/dist/", // necessary for lazy-loaded chunks
};

if (isDevMode) {
    output.filename = "[name].[hash:8].entry.js";
    output.chunkFilename = "[name].[hash:8].chunk.js";
} else {
    output.filename = "[name].[chunkhash].entry.js";
    output.chunkFilename = "[name].[chunkhash].chunk.js";
}

/* -------------------------------------------------- OPTIMIZATION -------------------------------------------------- */

let optimization = {
    splitChunks: {
        chunks: "all",
        // divide by all libs
        // maxInitialRequests: Infinity,
        // dibide on 5 chunks
        maxInitialRequests: 1,
        minSize: 0,

        cacheGroups: {
            highcharts: {
                test: /[\\/]node_modules[\\/]highcharts/,
                enforce: true,
                name: "npm.highcharts",
            },
            react_dom: {
                test: /[\\/]node_modules[\\/]react-dom/,
                enforce: true,
                name: "npm.react-dom",
            },
            vendor: {
                test: /[\\/]node_modules[\\/]/,
                name(js_module) {
                    // get the name. E.g. node_modules/packageName/not/this/part.js
                    // or node_modules/packageName
                    const packageName = js_module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
                    // npm package names are URL-safe, but some servers don't like @ symbols
                    return `npm.${packageName.replace("@", "")}`;
                },
            },
        },
    },

    // minimize code in production
    minimize: !isDevMode,
    minimizer: isDevMode ? null :  [
        new TerserPlugin({
            cache: ".terser-plugin-cache/",
            parallel: true,
            extractComments: true,
            sourceMap: false,
        }),
    ],
};

/* --------------------------------------- RESOLVE PATHS TO MODULES ANF FILES --------------------------------------- */
let resolve = {
    alias: {
        src: path.resolve(APP_DIR, "./src"),
        Components: path.resolve(__dirname, "./src/modules/Components/"),
        Services: path.resolve(__dirname, "./src/modules/Services/"),
        Utils: path.resolve(__dirname, "./src/modules/Utils/"),
        Styles: path.resolve(__dirname, "./stylesheets/"),
        Images: path.resolve(__dirname, "./images/"),
        Icons: path.resolve(__dirname, "./images/icons/"),
    },
    extensions: [".ts", ".tsx", ".js", ".jsx", ".svg", ".png", ".css", ".less"],
    symlinks: false,
};

/* ------------------------------------------------ MODULES / LOADERS ----------------------------------------------- */
let loaders = {
    rules: [
        { test: /\.jsx?$/,
          exclude: /node_modules/,
          include: APP_DIR,
          loader: "babel-loader",
        },
        { test: /\.css$/,
          include: APP_DIR,
          use: [
              isDevMode ? "style-loader" : MiniCssExtractPlugin.loader,
              "css-loader",
          ],
        },
        { test: /\.less$/,
          include: APP_DIR,
          use: [
              isDevMode ? "style-loader" : MiniCssExtractPlugin.loader,
              "css-loader",
              "less-loader",
          ],
        },
        /* for css linking images */
        { test: /\.png$/,
          loader: "url-loader",
          options: {
              limit: 10000,
              name: "[name].[hash:8].[ext]",
          },
        },
        { test: /\.(jpg|gif)$/,
          loader: "file-loader",
          options: {
              name: "[name].[hash:8].[ext]",
          },
        },
        /* for font-awesome */
        { test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
          loader: "url-loader?limit=10000&mimetype=application/font-woff",
        },
        { test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
          loader: "file-loader",
          options: {
              name: "[name].[hash:8].[ext]",
          },
        },
    ],
};

/* --------------------------------------------------- DEV SERVER --------------------------------------------------- */
let devServer = {
    historyApiFallback: true,
    hot: true,
    index: "", // This line is needed to enable root proxying
    inline: true,
    stats: { colors:true },
    overlay: true,
    port: devserverPort,
    // Only serves bundled files from webpack-dev-server
    // and proxy everything else to backend
    proxy: {
        context: () => true,
        "/": `http://localhost:${portalPort}`,
        target: `http://localhost:${portalPort}`,
    },
    contentBase: path.join(process.cwd(), "../static/assets/dist"),
};

/* ------------------------------------------------- GENERAL CONFIG ------------------------------------------------- */
const config = {
    node: { fs:"empty" },
    devtool: isDevMode ? "inline-source-map" : false,
    entry: {},
    output,
    optimization: optimization,
    resolve,
    module: loaders,
    plugins,
    devServer,
};

/* ------------------------------------------------- GET ENTRYPOINTS ------------------------------------------------ */
const readFileTree = (dir) => fs
    .readdirSync(dir)
    .reduce((files, file) => (fs.statSync(path.join(dir, file)).isDirectory() ?
        files.concat(readFileTree(path.join(dir, file))) :
        files.concat(path.join(dir, file))), []);

let all_files = readFileTree("src");
all_files = all_files.filter((file) => /\/_index.jsx?/i.test(file));

all_files.forEach((file) => {
    let chunk_name = path.relative("./src", file).slice(0, -10);
    let entry_name = chunk_name.replace(/\//g, ".").replace(/\.$|^\./, "");
    config.entry[entry_name] = path.resolve(__dirname, file);
});

/* ----------------------------------------------- MEASURE BUILD TIME ----------------------------------------------- */
// Speed measurement is disabled by default
// Pass flag --measure=true to enable
// e.g. npm run build -- --measure=true
const smp = new SpeedMeasurePlugin({
    disable: !measure,
});

module.exports = smp.wrap(config);

Operating system

ubuntu 19.10

webdeveric commented 4 years ago

@Serzh470 This should be fixed in my next release that I'm working on now.