Reputation: 1456
For some internal tooling I'm trying to write source filenames into the javascript source using webpack. I came up with the code below. Unfortunately, while it does replace '[filename]' in the provided AST, that change seems to be thrown away. Is the AST read-only in this context? (And possibly, how can you do this if not this way?)
const NAME = 'InjectFilenamePlugin'
const SOURCE_TEST = /src/i // a path to ensure node_modules are bypassed
const PLACEHOLDER = '[filename]'
class InjectFilenamePlugin {
apply(compiler) {
compiler.hooks.compilation.tap(NAME, (_, params) => {
const { normalModuleFactory } = params
function handler(parser) {
parser.hooks.program.tap(NAME, (ast) => {
const { resource } = parser.state.module
if (SOURCE_TEST.test(resource) && ast) {
replacePlaceholder(ast)
}
function replacePlaceholder(node) {
if (node.value === PLACEHOLDER) {
node.value = resource
node.raw = `"${resource}"`
} else {
Object.values(node)
.filter(node => node && typeof node === 'object')
.forEach(replacePlaceholder)
}
}
})
}
normalModuleFactory.hooks.parser
.for('javascript/auto')
.tap(NAME, handler)
normalModuleFactory.hooks.parser
.for('javascript/dynamic')
.tap(NAME, handler)
normalModuleFactory.hooks.parser
.for('javascript/esm')
.tap(NAME, handler)
})
}
}
module.exports = InjectFilenamePlugin
Upvotes: 3
Views: 851