Webpack输出HTML文件未保留原目录结构问题求助
项目背景
将基于Gulp+Foundation for Sites SCSS框架的法学案例书网站迁移至Webpack,对Webpack不熟悉。项目src目录结构如下:
/src /views /layouts /partials /pages /teaching 4个内部HTML文件 index.html 2个其他顶级HTML文件
注:项目入口为/src/assets/js/app.ts,该文件内通过@import引入/src/assets/scss/app.scss,这部分构建正常。
当前HTML构建配置
1. html-webpack-plugin 配置
const htmlPages = glob.sync('./src/views/pages/**/*.html').map(page => { const filename = path.basename(page); return new HtmlWebpackPlugin({ template: page, filename: filename, inject: true }); });
2. Nunjucks模板加载规则
// Nunjucks templates { test: /\.html$/, // exclude: /src\/views\/pages\/.*\.html$/, /* <- break rule experiment */ use: [ { loader: 'html-loader', options: { sources: false, minimize: PRODUCTION, esModule: false } }, { loader: 'nunjucks-html-loader', options: { searchPaths: [ path.resolve(__dirname, 'src/views/') ], context: { // Global context variables for templates PRODUCTION: PRODUCTION } } } ] },
3. 插件引入
plugins: [ ...htmlPages ]
问题现象
期望dist目录结构:
/dist /teaching 4个HTML文件 index.html 2个其他HTML文件
实际生成结果:7个HTML文件全部直接输出在dist根目录,未保留原目录结构。
原因分析
问题核心出在html-webpack-plugin的filename配置上:你使用path.basename(page)提取文件名,这个方法只会返回文件的纯名称(比如/src/views/pages/teaching/file.html会被提取为file.html),完全丢弃了文件所在的目录层级,导致所有文件都被输出到dist根目录。
加载器配置和目录结构问题无关——之前修改正则或添加exclude导致模板内容丢失,是因为破坏了模板的处理流程,但并非目录结构异常的原因。
解决方案
计算每个HTML文件相对于src/views/pages的相对路径,将该路径作为filename的值,即可保留原目录结构。修改后的htmlPages代码如下:
const pagesRoot = path.resolve(__dirname, 'src/views/pages'); const htmlPages = glob.sync('./src/views/pages/**/*.html').map(page => { // 获取文件相对于pages根目录的路径 const relativePath = path.relative(pagesRoot, page); return new HtmlWebpackPlugin({ template: page, filename: relativePath, inject: true }); });
修改后,src/views/pages/teaching/file.html对应的relativePath为teaching/file.html,输出时会自动生成dist/teaching/file.html;顶级的index.html则直接输出到dist/index.html,完全符合预期结构。
内容的提问来源于stack exchange,提问作者Frank Burleigh

