Webpack 5 资源模块 (asset/resource) 使所有 SVG 消失。

3

Webpack 不是我的强项,今天我在一个巨大的项目中遇到了一个问题,完全卡住了。

基本上我只是运行了 webpack 分析器,发现我们的打包文件大小太大了,因为在我们的项目构建中有约 200 个 SVG。 我想出一个简单的解决方案来减小打包文件的大小并使用 webpack 压缩 SVG,因为这是我们正在使用的工具。 经过多次失败尝试后,我认为只需包含以下代码就可以轻松解决问题:

     test: /\.(gif|png|jpe?g|svg)$/i,
     type: 'asset/resource',
    },

我现在可以看到我的捆绑包明显减少了,但当我加载项目时,所有的SVG都被隐藏了。

可能的原因是什么?另外,使用Webpack 5压缩SVG的替代方法是什么?

以下是完整的Webpack配置:

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const SpriteLoaderPlugin = require('svg-sprite-loader/plugin');
const { WebpackManifestPlugin } = require('webpack-manifest-plugin');

const hashSubstr = '.[contenthash:8]';

const svgoPlugins = [
    { cleanUpAttrs: true },
    { removeDoctype: true },
    { removeXMLProcInst: true },
    { removeComments: true },
    { removeMetadata: true },
    { removeDesc: true },
    { removeEditorsNSData: true },
    { removeEmptyAttrs: true },
    { removeHiddenElems: true },
    { removeEmptyText: true },
    { removeEmptyContainers: true },
    { cleanupNumericValues: true },
    { moveElemsAttrsToGroup: true },
    { convertColors: { shorthex: true } },
];

module.exports = (env) => ({
    entry: ['./scripts/responsive/index.ts', './scripts/pwa/serviceworker.ts'],
    output: {
        filename: `[name]${!env.development ? hashSubstr : ''}.js`,
        globalObject: 'this',
        path: path.resolve(__dirname, './bundles/responsive'),
        publicPath: '/',
        assetModuleFilename: '[hash][ext][query]',
    },
    mode: !env.development ? 'production' : 'development',
    devtool: 'inline-source-map',
    optimization: {
        minimize: true,
    },
    module: {
        rules: [
            // {
            //  test: /\.(gif|png|jpe?g|svg)$/i,
            //  type: 'asset/resource',
            // },
            {
                test: /\.(jsx?|tsx?)$/,
                loader: 'babel-loader',
                options: {
                    presets: ['@babel/typescript', '@babel/env'],
                },
            },
            {
                test: /\.s[ac]ss$/i,
                use: [
                    {
                        loader: MiniCssExtractPlugin.loader,
                        options: {
                            publicPath: '../',
                        },
                    },
                    {
                        loader: 'css-loader',
                        options: {
                            sourceMap: true,
                        },
                    },
                    {
                        loader: 'sass-loader',
                        options: {
                            sourceMap: true,
                        },
                    },
                ],
            },
            {
                test: /\-colou?r\.svg$/,
                type: 'asset/resource',
                include: [path.resolve(__dirname, 'Content/responsive/svg')],
                use: [
                    {
                        loader: 'svg-sprite-loader',
                        options: {
                            spriteFilename: 'sprite.svg',
                            esModule: false,
                            symbolId: (fileName) => {
                                return `r-icon-${path.basename(fileName, '.svg')}`;
                            },
                        },
                    },
                    {
                        loader: 'svgo-loader',
                        options: {
                            plugins: svgoPlugins,
                        },
                    },
                ],
            },
            {
                test: /\.svg$/,
                type: 'asset/resource',
                exclude: /-colou?r\.svg$/,
                include: [path.resolve(__dirname, 'Content/responsive/svg')],
                use: [
                    {
                        loader: 'svg-sprite-loader',
                        options: {
                            spriteFilename: 'sprite.svg',
                            esModule: false,
                            symbolId: (fileName) => {
                                return `r-icon-${path.basename(fileName, '.svg')}`;
                            },
                        },
                    },
                    {
                        loader: 'svgo-loader',
                        options: {
                            plugins: [
                                {
                                    removeAttrs: {
                                        attrs: '(?!mask).*:(stroke|fill)',
                                    },
                                },
                                ...svgoPlugins,
                            ],
                        },
                    },
                ],
            },
        ],
    },
    //stats: 'verbose',
    plugins: [
        new ForkTsCheckerWebpackPlugin(),
        new WebpackManifestPlugin({
            fileName: 'asset-manifest.json',
            generate: (seed, files) => {
                const manifestFiles = files.reduce((manifest, file) => {
                    manifest[file.name] = file.path;
                    return manifest;
                }, seed);

                const entrypointFiles = files
                    .filter((x) => x.isInitial && !x.name.endsWith('.map'))
                    .map((x) => x.path);

                return {
                    files: manifestFiles,
                    entrypoints: entrypointFiles,
                };
            },
        }),
        new MiniCssExtractPlugin({
            // Options similar to the same options in webpackOptions.output
            // both options are optional
            filename: `css/[name]${!env.development ? hashSubstr : ''}.css`,
            chunkFilename: `css/[id]${!env.development ? hashSubstr : ''}.css`,
        }),
        new SpriteLoaderPlugin({
            plainSprite: true,
        }),
    ],
    resolve: {
        extensions: ['.js', '.jsx', '.ts', '.tsx'],
        alias: {
            Svg: path.resolve(__dirname, './Content/responsive/svg'),
        },
    },
});

1个回答

0
在我的情况下,似乎当使用 type: 'asset/resource' 时,该模块被导出为 commonjs 而不是 esmodule 的默认导入。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接