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