alecmce
alecmce

Reputation: 1456

(How) can you manipulate AST in Webpack compilation hook?

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

Answers (0)

Related Questions