webpack4.44构建时webpack-manifest-plugin未包含全部manifest条目问题
Angular 11非watch构建webpack-manifest-plugin丢失静态资源解决方案
问题根因
@angular-devkit/build-angular 0.1001+版本升级webpack 4.44后,生产非watch模式下会将未被js/ts直接引用的静态资源标记为「额外资源」,走Angular自研的复制逻辑,不会被webpack默认的asset管道捕获,因此webpack-manifest-plugin无法扫描到这部分资源;watch模式下为了支持增量构建,静态资源仍然走webpack标准loader流程,所以可以正常生成。
可落地解决方案
方案1:自定义webpack-manifest-plugin生成逻辑
无需调整依赖版本,直接修改webpack配置中manifest插件的生成规则,手动扫描补充静态资源:
const fs = require('fs'); const path = require('path'); const ManifestPlugin = require('webpack-manifest-plugin'); // 对应项目src/assets目录路径 const ASSETS_ROOT = path.resolve(__dirname, 'src/assets'); // 静态资源输出的public前缀 const ASSETS_PUBLIC_PREFIX = 'hybrid/assets/'; // 递归扫描assets目录下所有文件 function scanAssets(dir, prefix = '') { const assetMap = {}; const items = fs.readdirSync(dir); items.forEach(item => { const fullPath = path.join(dir, item); const stat = fs.statSync(fullPath); if (stat.isDirectory()) { Object.assign(assetMap, scanAssets(fullPath, `${prefix}${item}/`)); } else { const assetKey = `assets/${prefix}${item}`; assetMap[assetKey] = `${ASSETS_PUBLIC_PREFIX}${prefix}${item}`; } }); return assetMap; } module.exports = { plugins: [ new ManifestPlugin({ fileName: 'manifest.json', publicPath: 'hybrid/', // 自定义生成逻辑,合并webpack生成的资源和手动扫描的静态资源 generate: (seed, files) => { const baseManifest = files.reduce((manifest, file) => { manifest[file.name] = file.path; return manifest; }, seed); const extraAssets = scanAssets(ASSETS_ROOT); return { ...baseManifest, ...extraAssets }; } }) ] }
方案2:锁定兼容版本依赖
Angular 11可兼容未引入问题变更的@angular-devkit/build-angular@0.1100.0版本,直接在package.json中固定版本即可:
{ "dependencies": { "@angular-devkit/build-angular": "0.1100.0" }, "resolutions": { "@angular-devkit/build-angular": "0.1100.0", "webpack": "4.43.0" } }
修改后删除node_modules和lock文件,重新执行安装即可,该版本完全兼容Angular 11核心包和angular-hybrid依赖。
方案3:后置脚本补全manifest
如果不想修改构建配置和依赖,可新增postbuild脚本,构建完成后自动扫描dist目录所有资源生成完整manifest:
- 新建
build-manifest.js脚本:
const fs = require('fs'); const path = require('path'); // 构建产物输出目录 const DIST_DIR = path.resolve(__dirname, 'dist/hybrid'); const PUBLIC_PREFIX = 'hybrid/'; function walkDistDir(dir, prefix = '') { const manifest = {}; fs.readdirSync(dir).forEach(file => { const fullPath = path.join(dir, file); if (fs.statSync(fullPath).isDirectory()) { Object.assign(manifest, walkDistDir(fullPath, `${prefix}${file}/`)); } else { const key = prefix ? `${prefix}${file}` : file; // 过滤掉manifest.json自身 if (key !== 'manifest.json') { manifest[key] = `${PUBLIC_PREFIX}${key}`; } } }); return manifest; } const fullManifest = walkDistDir(DIST_DIR); fs.writeFileSync(path.join(DIST_DIR, 'manifest.json'), JSON.stringify(fullManifest, null, 2));
- 修改package.json的构建脚本:
{ "scripts": { "build": "ng build --prod && node build-manifest.js" } }
内容的提问来源于stack exchange,提问作者ema
相关产品推荐
相关产品推荐

