12

我有一个项目结构,其中包含一个文件夹,我想在构建 webpack 配置时动态导入到 UMD 模块中,并使每个文件成为输出构建中的子模块。

例如,假设我的来源看起来像:

/src/snippets/red.js
/src/snippets/green.js
/src/snippets/blue.js

我希望 webpack 将这些源构建到一个模块中,这样我就可以将每个源都作为子模块来访问,就像这样;

const red = require('snippets').red

我尝试遍历片段目录并使用文件名和路径创建一个对象,但我无法弄清楚哪个配置属性将指示 webpack 将它们捆绑到一个文件中并导出每个文件。这是我到目前为止所拥有的:

const glob = require('glob')

module.exports = {
    entry: glob.sync('./src/snippets/*.js').reduce((files, file) => {
        files[path.basename(file,'.js')] = file

        return files
    }, {}),
    output: {
      path: __dirname + '/lib',
      filename: 'snippets.js',
      libraryTarget: 'umd'
    }
}

这会出错:Conflict: Multiple assets emit to the same filename ./lib/snippets.js

关于如何完成我正在寻找的任何想法?

4

3 回答 3

3

一段时间以来一直在生产中使用此解决方案的修改版本,我对此没有任何问题。(我公司的设置有一个稍微复杂的过滤器,以排除某些模拟模块,但其他方面是相同的)。

我们使用构建脚本来爬取有问题的目录(在我们的设置中,它src在您的src/snippets.js 中。对于每个以 .js 结尾的文件,我们将其导入并重新导出为src/index.js. 如果您需要更强大的东西,比如去多层次的深度,您需要修改它以递归遍历目录结构。

完成后,我们将其输出到 index.js,并提醒该文件是自动生成的,以阻止人们手动将条目添加到文件中。

const fs = require("fs");
const { EOL } = require("os");
const path = require("path");

let modules = 0;
const buffer = [
  "// auto-generated file", "",
];

const emitModule = file => {
  const moduleName = file.replace(".js", "");
  modules += 1;
  buffer.push(`exports.${moduleName} = require("./snippets/${moduleName}");`);
};

const files = fs.readdirSync(__dirname + "/snippets");

files
.filter(fname => fname !== "index.js" && !fname.startsWith("."))
.forEach(f => {
  const stats = fs.statSync(path.join(__dirname, "snippets", f));
  if (stats.isFile()) {
    emitModule(f);
  }
});

fs.writeFileSync(path.join(__dirname, "index.js"), buffer.join(EOL)+EOL);

console.info(`Built 'src/index.js' with ${modules} modules`);

然后,在 webpack.config.js 中,我们将 libraryTarget 设置umd为如下:

module.exports = {
  entry: path.resolve(__dirname, "src/index.js"),
  output: {
    path: path.resolve(__dirname, "build/"),
    filename: "mylib.js",
    libraryTarget: "umd"
  }
};

最后,为方便起见,在 package.json 中,我们使用以下内容在构建之前自动运行构建脚本(您也可以在启动 webpack-dev-server 或运行 mocha 测试之前使用它)。

这种设置感觉相当hacky,但效果很好。我遇到的唯一问题是,模块的顺序偶尔会发生变化(大概是因为环境差异),并且文件的枚举会导致 git 中的误报。

我把整个包放在 GitHub 上:https ://github.com/akatechis/webpack-lib-poc


更新:如果您不想通过将构建脚本添加到您的 package.json 来手动调用它scripts,您可以随时将其包装为 webpack 插件。您可以在此处阅读详细信息

简而言之,插件只是一个对象,apply它具有向 webpack 编译器注册自身的方法。从文档:

作为一个聪明的 JavaScript 开发人员,您可能还记得这个Function.prototype.apply方法。由于这种方法,您可以将任何函数作为插件传递(this将指向编译器)。您可以使用此样式在配置中内联自定义插件。

以下是两种设置之间的变化:

更改 webpack 配置以导入构建脚本并将其添加到plugins数组中:

const path = require("path");
const buildPlugin = require("./src/index.build");

module.exports = {
  entry: path.resolve(__dirname, "src/index.js"),
  output: {
    path: path.resolve(__dirname, "build/"),
    filename: "mylib.js",
    libraryTarget: "umd"
  },
  plugins: [buildPlugin]
};

然后更改index.build.js导出一个在编译器上注册回调的函数(它接收它作为this)。把之前构建脚本的内容,放到一个build()函数中,然后导出一个插件函数,如下:

module.exports = function () {
  this.plugin('run', function(compiler, callback) {
    console.log("Build script starting");
    build();
    callback();
  });
};

从. build-index_ package.jsonWebpack 现在将始终在运行之前调用您的构建脚本。

于 2018-01-29T01:32:30.187 回答
0

尝试这个:

我基本上是在稍微不同地更改条目,然后进一步使用 NamedModulesPlugin。

module.exports = {
    entry: glob.sync('./snippets/*.js').reduce(function(entry, file){
        entry['./snippets'].push(file);
        return entry;
    }, { './snippets': []}),
    output: {
        path: path.resolve(__dirname, ''),
        filename: '[name].js'
        libraryTarget: 'umd'
    },
    module: {
        // only relevant portions shown
        plugins: [
            new webpack.NamedModulesPlugin()
        ]
    }
};

它应该工作。

于 2018-01-23T17:30:23.010 回答
-1

看起来类似于conflict-multiple-assets-emit-to-the-same-filename这个已解决的问题,所以它可能对您有所帮助。我在某处看到这也可能是由于您的一个(或多个)模块插件不支持打包。

于 2018-01-22T02:54:39.730 回答