Webpack:我可以从字符串中提供“虚拟”文件吗?

时间:2015-11-05 10:30:34

标签: webpack

我有一些在构建时在我的Webpack应用程序中创建的JSON - 有什么方法可以在构建期间“注入”它的路径?我知道我可以把它写到文件中并以这种方式包含它,但我希望我能做一些比这更清洁的事情。

1 个答案:

答案 0 :(得分:8)

编辑2018/04/09: val-loader是在构建时实现注入代码和值的另一种方法,但它需要从单独的文件加载该代码,这可能不是如果仅存在于内存中,则能够访问OP设置中的JSON数据。

我一直在寻找一种方法来做到这一点。我最终深入研究了webpack的内部,并编写了一个似乎有用的插件。

它很简洁,你不必将文件写入磁盘,但它的内部有点乱,因为我必须了解webpack的CachedInputFileSystem是如何工作的。

使用装载机似乎无法做到这一点。 Webpack需要解析磁盘上的文件位置,并在进入加载阶段之前读取其中的内容。

通过在compiler.resolvers.normal的'resolve'阶段放置一个插件函数,可以访问webpack使用的文件系统,然后将虚拟文件名和内容添加到该文件系统的缓存中。

执行此操作后,其他所有内容在webpack中正常工作,您的虚拟文件/模块将通过您已配置的其他加载器和插件。

有关我编写的代码,请参阅https://github.com/rmarscher/virtual-module-webpack-plugin。它已发布到npm:https://www.npmjs.com/package/virtual-module-webpack-plugin

以下是插件解析部分的代码。请注意,此示例适用于webpack 1和2,但该插件已更新以适用于更新版本:

compiler.resolvers.normal.plugin('resolve', function resolverPlugin(request, cb) {
  // populate the file system cache with the virtual module
  const fs = this.fileSystem;

  // webpack 1.x compatibility
  if (typeof request === 'string') {
    request = cb;
    cb = null;
  }

  if (!modulePath) {
    modulePath = this.join(compiler.context, moduleName);
  }
  VirtualModulePlugin.populateFilesystem({ fs, modulePath, contents, ctime });
  if (cb) {
    cb();
  }
});

populateFilesystem静态方法将内容添加到fs._readFileStorage.data,并在fs.stat()缓存中为fs._statStorage.data创建模拟结果。为了创建模拟fs.Stats对象,我借用了mock-fs package中的一些代码。

到目前为止,我已经使用最新的webpack 1.x和2.x以及webpack-dev-server对其进行了测试。我使用了extract-text-webpack-pluginjson-loaderraw-loadercss-loader。所有似乎都按预期工作。

这是一个使用插件的webpack配置:

'use strict';

const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const VirtualModulePlugin = require('virtual-module-webpack-plugin');

module.exports = function webpackConfig() {
  const runtimeJsonContents = JSON.stringify({
    greeting: 'Hello!',
  });
  const runtimeStyleContents = `
    body { background: #000; color: #ccc; }
    .greeting { font: 600 40px/50px fantasy; text-align: center; }
  `;

  const config = {
    context: __dirname,
    devtool: 'source-map',
    entry: {
      index: './src/index',
    },
    output: {
      filename: '[name].js',
      path: 'dist',
      publicPath: '/',
      devtoolModuleFilenameTemplate: '../[resource-path]',
    },
    module: {
      loaders: [
        {
          test: /\.json$/,
          loaders: ['json-loader'],
        },
        {
          test: /\.css$/,
          loader: ExtractTextPlugin.extract({
            fallbackLoader: 'style-loader',
            loader: 'css-loader?sourceMap',
          }),
        },
      ],
    },
    plugins: [
      new VirtualModulePlugin({
        moduleName: 'src/mysettings.json',
        contents: runtimeJsonContents,
      }),
      new VirtualModulePlugin({
        moduleName: 'src/css/generated.css',
        contents: runtimeStyleContents,
      }),
      new ExtractTextPlugin({
        filename: '[name].css',
        allChunks: true,
      }),
    ],
    resolve: {
      modules: [
        path.join(__dirname, 'src'),
        'node_modules',
      ],
    },
  };
  return config;
};

有关不同版本的webpack的完整示例,请参阅https://github.com/rmarscher/virtual-module-webpack-plugin/tree/master/examples

我还应该注意,此代码需要NodeJS 4.x或更高版本。