You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Webpack构建时执行NormalModule并保存结果至JSON文件?

Better Approaches to Execute Modules at Build Time in Webpack

Great question—this is a common pain point when building Webpack plugins that need to run module code during the build process, and you’re totally right that manually replacing Webpack-specific variables with eval is clunky and error-prone. Let’s break down some more robust, Webpack-native solutions:

1. Use Node.js vm Module for Sandboxed Execution

Direct eval pollutes the global environment and makes it hard to reliably inject all the Webpack-specific variables your module might need. Instead, Node.js’s vm module lets you create an isolated sandbox where you can explicitly pass in variables like __webpack_public_path__:

const { VM } = require('vm');
const { RawSource } = require('webpack-sources');

compilation.hooks.succeedModule.tap('YourPluginName', (module) => {
  // Target only your specific module(s)
  if (!module.userRequest.includes('path/to/your/target/module')) return;

  // Get the compiled source code of the module
  const moduleSource = module.source().source();

  // Build a sandbox context with all required Webpack variables
  const sandboxContext = {
    __webpack_public_path__: compilation.outputOptions.publicPath || '/',
    // Add other globals your module might depend on (e.g., console, require)
    console,
    module: { exports: {} },
    exports: {}
  };

  // Execute the module in the sandbox
  const vmInstance = new VM({ context: sandboxContext });
  vmInstance.runInContext(moduleSource);

  // Save the execution result as a JSON asset
  const resultJson = JSON.stringify(sandboxContext.module.exports, null, 2);
  compilation.emitAsset('module-execution-result.json', new RawSource(resultJson));
});

Why this works better:

  • Isolation: No global pollution, so your plugin won’t interfere with other build processes
  • Controlled variable injection: You can explicitly define every Webpack-specific variable your module needs, avoiding missing dependencies
  • Safety: Sandboxed execution reduces risks associated with running untrusted code

2. Fetch Compiled Assets Post-Build

If you prefer to handle execution after all modules are compiled, use the afterCompile hook to fetch the compiled asset and run it in a sandbox:

const { VM } = require('vm');
const { RawSource } = require('webpack-sources');

compiler.hooks.afterCompile.tapAsync('YourPluginName', (compilation, callback) => {
  // Find the compiled asset for your target module
  const targetAsset = compilation.getAsset('your-target-module.js');
  if (!targetAsset) {
    callback();
    return;
  }

  const assetSource = targetAsset.source.source();
  const sandboxContext = {
    __webpack_public_path__: compilation.outputOptions.publicPath || '/',
    module: { exports: {} },
    exports: {}
  };

  const vmInstance = new VM({ context: sandboxContext });
  vmInstance.runInContext(assetSource);

  // Emit the result as a JSON file
  compilation.emitAsset('module-result.json', new RawSource(JSON.stringify(sandboxContext.module.exports, null, 2)));
  callback();
});

This approach is ideal if you need to process multiple modules at once after the entire build is complete.

3. Build a Custom Loader for Targeted Execution

For a more modular approach, create a custom Webpack loader that runs your module code during the compilation phase and emits the result:

// execute-module-loader.js
const { VM } = require('vm');

module.exports = function(source) {
  // Access Webpack's publicPath from the loader context
  const publicPath = this._compilation.outputOptions.publicPath || '/';

  const sandboxContext = {
    __webpack_public_path__: publicPath,
    module: { exports: {} },
    exports: {}
  };

  const vmInstance = new VM({ context: sandboxContext });
  vmInstance.runInContext(source);

  // Emit the execution result as a JSON asset
  this.emitFile('module-execution-result.json', JSON.stringify(sandboxContext.module.exports, null, 2));

  // Return the original source so the module still works in the final bundle
  return source;
};

Then add it to your Webpack config for your target modules:

module.exports = {
  module: {
    rules: [
      {
        test: /your-target-module\.js$/,
        use: ['execute-module-loader'],
        enforce: 'post' // Run after other loaders have processed the module
      }
    ]
  }
};

This fits seamlessly into Webpack’s loader ecosystem and is great for handling multiple modules of the same type.

Why Avoid Manual eval?

  • Security Risks: eval runs code in the global context, which can lead to unintended side effects or security vulnerabilities
  • Variable Gaps: Webpack injects many hidden globals (like __webpack_require__ or __webpack_chunk_load__) that you’ll likely miss when manually replacing variables
  • Environment Mismatch: The eval environment doesn’t match the actual runtime environment Webpack provides, leading to inconsistent execution results

内容的提问来源于stack exchange,提问作者CGodo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:33:21