我正在寻找类似 html-webpack-plugin 的东西,但它不是 HTML,而是输出到加载其他所有内容的 javascript 文件。我找到了 js-entry-webpack-plugin,但它没有为我输出任何内容,并且似乎没有吐出任何有用的日志记录来告诉我原因。有没有其他东西,内置的或其他的,可以为我做到这一点?
背景
我有一个项目想要构建到一个库中(例如下划线或 jquery),该库可以使用 ES6 在浏览器中动态导入。该库的 API 非常简单,类似于
// index.js:
export const MyAPI = {
function1: <does stuff>,
function2: <does other stuff>
}
所以导入它应该是一件轻而易举的事,但我想以 CDN 方式发布它,所以必须动态导入:
// example.js:
const { MyAPI } = await import(<url to MyAPI.js>)
我已在 webpack.config.js 中进行了更改以输出到库:
// webpack.config.js:
experiments: {
outputModule: true
},
output: {
filename: 'static/js/[name].[contenthash:8].js',
path: path.resolve(__dirname, 'build'),
publicPath: '/',
chunkFilename: 'static/js/[name].[contenthash:8].chunk.js',
assetModuleFilename: ({ filename }) => {
return filename.endsWith('.css') ? 'static/css/[name].[contenthash:8].css' : 'static/media/[name].[hash][ext]'
},
library: {
type: 'module'
}
}
该项目产生了数十个 js 块,当我使用 html-webpack-plugin 时,我得到一个带有大量标签的 HTML 文件。我正在寻找一个工具,可以构建一个看起来像这样的 javascript 文件。请注意,MyAPI 是唯一需要在项目外部可见的接口。
// MyAPI.js
import { a, b, c } from 'main.d7791ce7'
import { d, e, f } from '2.62a7f06e'
import { g, h, i } from '19.c38ba2b0.chunk'
... etc
export const MyAPI = {
function1: a.doSomething,
function2: d.doSomething,
...
}
我考虑过设置 webpack 来生成一个具有我想要的文件名的捆绑文件。我可以将其命名为 MyAPI.js,这样我的问题就可以解决。然而,我会错过分块和缓存清除的好处。我想使用这些功能,同时仍然生成一个漂亮、干净、具有已知名称(无哈希)的单个文件,该文件可以用作访问我的 API 的入口点。
我花了很长时间,但在了解了更多关于 webpack 工作原理的知识后我解决了这个问题。每个 webpack 包必然由需要在同一同步上下文中运行的代码组成。这可能是一种可怕的描述方式,但基本上,webpack 将一个文件视为一个单独的包的唯一方法是是否涉及
await import
。所以解决方案如下所示:
// index.js
const { a } = await import('./abc')
const { d } = await import('./def')
export default {
function1: a.doSomething,
function2: d.doSomething
}
由于index.js中没有任何内容需要abc或def中的任何内容现在,因此可以自由地单独捆绑index.js。然后,由于其他所有内容都位于单独的捆绑包中,因此无需指向已编译的捆绑包名称。然后我在 webpack.config.js 中的命名系统中添加一个例外:
output: {
filename: (pathData) => {
return pathData.chunk.name?.includes('index') ? 'static/js/MyAPI.js' : 'static/js/[name].[contenthash:8].js'
}
}
所以现在主包始终称为 MyAPI.js,webpack 将根据需要自动加载其他包。所以我可以这样使用它:
import MyAPI from '/static/js/MyAPI.js'
MyAPI.a()
MyAPI.d()
如果我不输出到 ES6 模块,我不确定这是否有效。具体来说,我认为我无法将使用
await import
导入的内容与其他输出库类型导出。但它与 ES6 配合得很好——webpack 只是确保在此包加载和执行之前加载依赖项。