@rustwrap/webpack 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +106 -0
- package/bin/rollpack.js +82 -0
- package/lib/assets.js +58 -0
- package/lib/build.js +295 -0
- package/lib/compiler.js +307 -0
- package/lib/config.js +133 -0
- package/lib/css.js +103 -0
- package/lib/dev-server.js +176 -0
- package/lib/empty-module.js +2 -0
- package/lib/index.js +162 -0
- package/lib/loaders.js +211 -0
- package/lib/plugins.js +130 -0
- package/lib/sourcemap.js +13 -0
- package/lib/stats.js +60 -0
- package/lib/template.js +144 -0
- package/package.json +42 -0
package/lib/plugins.js
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Built-in webpack plugins. Bundler-affecting plugins (Define/Provide/Environment/Ignore/
|
|
4
|
+
* NormalModuleReplacement) populate `compiler.$rollpack`, which build.js reads during the Rolldown
|
|
5
|
+
* make phase. Asset-affecting plugins (Banner) tap compilation.processAssets. The rest are faithful
|
|
6
|
+
* no-ops or thin shims so configs load and run.
|
|
7
|
+
*/
|
|
8
|
+
const { STAGES } = require("./compiler");
|
|
9
|
+
|
|
10
|
+
function flattenDefinitions(defs, prefix, out) {
|
|
11
|
+
for (const [k, v] of Object.entries(defs || {})) {
|
|
12
|
+
const key = prefix ? `${prefix}.${k}` : k;
|
|
13
|
+
if (v && typeof v === "object" && !(v instanceof RegExp) && !Array.isArray(v)) flattenDefinitions(v, key, out);
|
|
14
|
+
else out[key] = typeof v === "string" ? v : (v instanceof RegExp ? v.toString() : JSON.stringify(v));
|
|
15
|
+
}
|
|
16
|
+
return out;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
class DefinePlugin {
|
|
20
|
+
constructor(definitions) { this.definitions = definitions || {}; }
|
|
21
|
+
apply(compiler) { Object.assign(compiler.$rollpack.define, flattenDefinitions(this.definitions, "", {})); }
|
|
22
|
+
}
|
|
23
|
+
DefinePlugin.runtimeValue = (fn, deps) => { const v = fn({}); return typeof v === "string" ? v : JSON.stringify(v); };
|
|
24
|
+
|
|
25
|
+
class EnvironmentPlugin {
|
|
26
|
+
constructor(...keys) { this.keys = Array.isArray(keys[0]) ? keys[0] : (typeof keys[0] === "object" ? keys[0] : keys); }
|
|
27
|
+
apply(compiler) {
|
|
28
|
+
const d = compiler.$rollpack.define;
|
|
29
|
+
if (Array.isArray(this.keys)) for (const k of this.keys) d[`process.env.${k}`] = JSON.stringify(process.env[k] !== undefined ? process.env[k] : "");
|
|
30
|
+
else for (const [k, def] of Object.entries(this.keys)) d[`process.env.${k}`] = JSON.stringify(process.env[k] !== undefined ? process.env[k] : def);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
class ProvidePlugin {
|
|
35
|
+
constructor(definitions) { this.definitions = definitions || {}; }
|
|
36
|
+
apply(compiler) { Object.assign(compiler.$rollpack.provide, this.definitions); }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
class BannerPlugin {
|
|
40
|
+
constructor(options) { this.options = typeof options === "string" ? { banner: options } : (options || {}); }
|
|
41
|
+
apply(compiler) {
|
|
42
|
+
const o = this.options;
|
|
43
|
+
const text = typeof o.banner === "function" ? o.banner : o.banner || "";
|
|
44
|
+
const make = (filename) => {
|
|
45
|
+
const raw = typeof text === "function" ? text({ filename }) : text;
|
|
46
|
+
if (o.raw) return raw;
|
|
47
|
+
return "/*! " + String(raw).replace(/\*\//g, "*\\/") + " */\n";
|
|
48
|
+
};
|
|
49
|
+
const test = o.test, include = o.include, exclude = o.exclude;
|
|
50
|
+
const matches = (name) => {
|
|
51
|
+
const m = (c, v) => c == null ? true : (c instanceof RegExp ? c.test(v) : (typeof c === "string" ? v.includes(c) : true));
|
|
52
|
+
if (!m(test, name)) return false;
|
|
53
|
+
if (include != null && !m(include, name)) return false;
|
|
54
|
+
if (exclude != null && m(exclude, name) && exclude != null) return false;
|
|
55
|
+
return /\.(js|mjs|cjs)$/.test(name) || test != null;
|
|
56
|
+
};
|
|
57
|
+
compiler.hooks.compilation.tap("BannerPlugin", (compilation) => {
|
|
58
|
+
compilation.hooks.processAssets.tap({ name: "BannerPlugin", stage: STAGES.PROCESS_ASSETS_STAGE_OPTIMIZE_INLINE }, (assets) => {
|
|
59
|
+
for (const name of Object.keys(assets)) {
|
|
60
|
+
if (!matches(name)) continue;
|
|
61
|
+
const src = assets[name];
|
|
62
|
+
const cur = src.source();
|
|
63
|
+
compilation.updateAsset(name, make(name) + (Buffer.isBuffer(cur) ? cur.toString("utf8") : cur));
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
class IgnorePlugin {
|
|
71
|
+
constructor(options) { this.options = (options && options.resourceRegExp) ? options : { resourceRegExp: options && options.checkResource ? undefined : options, checkResource: options && options.checkResource }; }
|
|
72
|
+
apply(compiler) { compiler.$rollpack.ignore.push(this.options); }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
class NormalModuleReplacementPlugin {
|
|
76
|
+
constructor(resourceRegExp, newResource) { this.resourceRegExp = resourceRegExp; this.newResource = newResource; }
|
|
77
|
+
apply(compiler) { compiler.$rollpack.normalReplace.push([this.resourceRegExp, this.newResource]); }
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
class ContextReplacementPlugin {
|
|
81
|
+
constructor(resourceRegExp, newContentResource) { this.resourceRegExp = resourceRegExp; this.newContentResource = newContentResource; }
|
|
82
|
+
apply() {}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
class SourceMapDevToolPlugin {
|
|
86
|
+
constructor(options) { this.options = options || {}; }
|
|
87
|
+
apply(compiler) { if (!compiler.options.devtool) compiler.options.devtool = this.options.inline ? "inline-source-map" : "source-map"; }
|
|
88
|
+
}
|
|
89
|
+
class EvalSourceMapDevToolPlugin {
|
|
90
|
+
constructor(options) { this.options = options || {}; }
|
|
91
|
+
apply(compiler) { if (!compiler.options.devtool) compiler.options.devtool = "inline-source-map"; }
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
class ProgressPlugin {
|
|
95
|
+
constructor(handler) { this.handler = typeof handler === "function" ? handler : (handler && handler.handler); }
|
|
96
|
+
apply(compiler) {
|
|
97
|
+
if (!this.handler) return;
|
|
98
|
+
compiler.hooks.run.tapPromise("ProgressPlugin", async () => { try { this.handler(0, "compiling"); } catch (_) {} });
|
|
99
|
+
compiler.hooks.done.tapPromise("ProgressPlugin", async () => { try { this.handler(1, "done"); } catch (_) {} });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Faithful no-ops (single-file output / behaviors already covered by Rolldown).
|
|
104
|
+
class NoopPlugin { constructor(options) { this.options = options; } apply() {} }
|
|
105
|
+
class LimitChunkCountPlugin extends NoopPlugin {}
|
|
106
|
+
class MinChunkSizePlugin extends NoopPlugin {}
|
|
107
|
+
class AggressiveMergingPlugin extends NoopPlugin {}
|
|
108
|
+
class ModuleConcatenationPlugin extends NoopPlugin {}
|
|
109
|
+
class RuntimeChunkPlugin extends NoopPlugin {}
|
|
110
|
+
class SplitChunksPlugin extends NoopPlugin {}
|
|
111
|
+
class WatchIgnorePlugin extends NoopPlugin {}
|
|
112
|
+
class LoaderOptionsPlugin extends NoopPlugin {}
|
|
113
|
+
class HotModuleReplacementPlugin { apply(compiler) { compiler.$rollpack = compiler.$rollpack || {}; compiler.$rollpack.hot = true; } }
|
|
114
|
+
class DllPlugin extends NoopPlugin {}
|
|
115
|
+
class DllReferencePlugin extends NoopPlugin {}
|
|
116
|
+
class HashedModuleIdsPlugin extends NoopPlugin {}
|
|
117
|
+
class NamedModulesPlugin extends NoopPlugin {}
|
|
118
|
+
class NamedChunksPlugin extends NoopPlugin {}
|
|
119
|
+
class NoEmitOnErrorsPlugin extends NoopPlugin {}
|
|
120
|
+
class ModuleFederationPlugin extends NoopPlugin {}
|
|
121
|
+
|
|
122
|
+
module.exports = {
|
|
123
|
+
DefinePlugin, EnvironmentPlugin, ProvidePlugin, BannerPlugin, IgnorePlugin,
|
|
124
|
+
NormalModuleReplacementPlugin, ContextReplacementPlugin, SourceMapDevToolPlugin,
|
|
125
|
+
EvalSourceMapDevToolPlugin, ProgressPlugin, LoaderOptionsPlugin, HotModuleReplacementPlugin,
|
|
126
|
+
WatchIgnorePlugin, DllPlugin, DllReferencePlugin, HashedModuleIdsPlugin, NamedModulesPlugin,
|
|
127
|
+
NamedChunksPlugin, NoEmitOnErrorsPlugin,
|
|
128
|
+
optimize: { LimitChunkCountPlugin, MinChunkSizePlugin, AggressiveMergingPlugin, ModuleConcatenationPlugin, RuntimeChunkPlugin, SplitChunksPlugin },
|
|
129
|
+
container: { ModuleFederationPlugin },
|
|
130
|
+
};
|
package/lib/sourcemap.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* webpack `devtool` -> Rolldown output.sourcemap option. */
|
|
3
|
+
function devtoolToRolldown(devtool) {
|
|
4
|
+
if (!devtool || devtool === "false" || devtool === false || devtool === "none") return { sourcemap: false, excludeSources: false };
|
|
5
|
+
const d = String(devtool);
|
|
6
|
+
let sourcemap = true;
|
|
7
|
+
if (d.includes("inline")) sourcemap = "inline";
|
|
8
|
+
else if (d.includes("hidden")) sourcemap = "hidden";
|
|
9
|
+
// eval-* variants aren't supported by Rolldown; approximate with inline maps.
|
|
10
|
+
else if (d.includes("eval")) sourcemap = "inline";
|
|
11
|
+
return { sourcemap, excludeSources: d.includes("nosources") };
|
|
12
|
+
}
|
|
13
|
+
module.exports = { devtoolToRolldown };
|
package/lib/stats.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* webpack-compatible Stats built from a Compilation's assets/errors/warnings. */
|
|
3
|
+
|
|
4
|
+
function createStats(compilation) {
|
|
5
|
+
const errors = compilation.errors || [];
|
|
6
|
+
const warnings = compilation.warnings || [];
|
|
7
|
+
const time = compilation.__time || 0;
|
|
8
|
+
const assetList = Object.keys(compilation.assets).map((name) => {
|
|
9
|
+
const src = compilation.assets[name];
|
|
10
|
+
const content = src.source();
|
|
11
|
+
return { name, size: Buffer.isBuffer(content) ? content.length : Buffer.byteLength(String(content), "utf8"), info: compilation.assetsInfo.get(name) || {}, chunks: [], chunkNames: [], emitted: true };
|
|
12
|
+
});
|
|
13
|
+
const normErr = (e) => (e && typeof e === "object") ? { message: e.message || String(e), stack: e.stack, moduleName: e.moduleName } : { message: String(e) };
|
|
14
|
+
|
|
15
|
+
const stats = {
|
|
16
|
+
compilation,
|
|
17
|
+
startTime: compilation.__startTime || 0,
|
|
18
|
+
endTime: (compilation.__startTime || 0) + time,
|
|
19
|
+
hasErrors: () => errors.length > 0,
|
|
20
|
+
hasWarnings: () => warnings.length > 0,
|
|
21
|
+
toJson(opts) {
|
|
22
|
+
return {
|
|
23
|
+
version: require("../package.json").version,
|
|
24
|
+
rollpack: true,
|
|
25
|
+
hash: compilation.hash || "",
|
|
26
|
+
time,
|
|
27
|
+
builtAt: Date.now(),
|
|
28
|
+
publicPath: (compilation.outputOptions && compilation.outputOptions.publicPath) || "",
|
|
29
|
+
outputPath: compilation.compiler.outputPath,
|
|
30
|
+
assetsByChunkName: {},
|
|
31
|
+
assets: assetList,
|
|
32
|
+
chunks: [],
|
|
33
|
+
modules: [],
|
|
34
|
+
entrypoints: {},
|
|
35
|
+
namedChunkGroups: {},
|
|
36
|
+
errors: errors.map(normErr),
|
|
37
|
+
warnings: warnings.map(normErr),
|
|
38
|
+
errorsCount: errors.length,
|
|
39
|
+
warningsCount: warnings.length,
|
|
40
|
+
children: [],
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
toString(opts) {
|
|
44
|
+
const useColors = opts && (opts === true || opts.colors);
|
|
45
|
+
const C = useColors ? { d: "\x1b[2m", g: "\x1b[32m", c: "\x1b[36m", y: "\x1b[33m", r: "\x1b[0m" } : { d: "", g: "", c: "", y: "", r: "" };
|
|
46
|
+
const lines = [];
|
|
47
|
+
for (const e of errors) lines.push(`${C.y}ERROR${C.r} ` + (e.message || String(e)));
|
|
48
|
+
for (const w of warnings) lines.push(`${C.y}WARNING${C.r} ` + (w.message || String(w)));
|
|
49
|
+
const total = assetList.reduce((s, a) => s + a.size, 0);
|
|
50
|
+
lines.push(`${C.c}rollpack${C.r} ${C.g}${assetList.length} assets${C.r} ${C.d}${fmt(total)} in ${time}ms${C.r}`);
|
|
51
|
+
for (const a of assetList) lines.push(` ${C.d}asset${C.r} ${C.c}${a.name}${C.r} ${fmt(a.size)}`);
|
|
52
|
+
return lines.join("\n");
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
return stats;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function fmt(b) { return b > 1048576 ? (b / 1048576).toFixed(2) + " MiB" : (b / 1024).toFixed(1) + " KiB"; }
|
|
59
|
+
|
|
60
|
+
module.exports = { createStats };
|
package/lib/template.js
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const crypto = require('crypto');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
const DEFAULT_HASH_LENGTH = 20;
|
|
7
|
+
|
|
8
|
+
function hasValue(value) {
|
|
9
|
+
return value !== undefined && value !== null;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function asString(value) {
|
|
13
|
+
return hasValue(value) ? String(value) : '';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function normalizeLength(len) {
|
|
17
|
+
if (!hasValue(len)) {
|
|
18
|
+
return DEFAULT_HASH_LENGTH;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const parsed = Number(len);
|
|
22
|
+
return Number.isFinite(parsed) ? Math.max(0, Math.floor(parsed)) : DEFAULT_HASH_LENGTH;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function getHash(content, len) {
|
|
26
|
+
const length = normalizeLength(len);
|
|
27
|
+
const input = hasValue(content) ? content : '';
|
|
28
|
+
const algorithm = crypto.getHashes().includes('md4') ? 'md4' : 'sha256';
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
return crypto.createHash(algorithm).update(input).digest('hex').slice(0, length);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
// Some OpenSSL builds list md4 but still reject it at runtime.
|
|
34
|
+
return crypto.createHash('sha256').update(input).digest('hex').slice(0, length);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function basename(resourcePath) {
|
|
39
|
+
if (!hasValue(resourcePath)) {
|
|
40
|
+
return '';
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return path.win32.basename(path.posix.basename(String(resourcePath)));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function derivedExt(vars) {
|
|
47
|
+
if (hasValue(vars.ext)) {
|
|
48
|
+
return String(vars.ext);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const base = basename(vars.resourcePath);
|
|
52
|
+
return base ? path.extname(base) : '';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function derivedName(vars) {
|
|
56
|
+
if (hasValue(vars.name)) {
|
|
57
|
+
return String(vars.name);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const base = basename(vars.resourcePath);
|
|
61
|
+
const ext = base ? path.extname(base) : '';
|
|
62
|
+
return ext ? base.slice(0, -ext.length) : base;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function derivedBase(vars) {
|
|
66
|
+
const base = basename(vars.resourcePath);
|
|
67
|
+
if (base) {
|
|
68
|
+
return base;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const name = derivedName(vars);
|
|
72
|
+
const ext = derivedExt(vars);
|
|
73
|
+
return name || ext ? name + ext : '';
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function relativePath(vars) {
|
|
77
|
+
if (!hasValue(vars.resourcePath) || !hasValue(vars.context)) {
|
|
78
|
+
return '';
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const resourcePath = String(vars.resourcePath);
|
|
82
|
+
const context = String(vars.context);
|
|
83
|
+
const directory = path.dirname(resourcePath);
|
|
84
|
+
|
|
85
|
+
if (!directory || directory === '.') {
|
|
86
|
+
return '';
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const relative = path.relative(context, directory);
|
|
90
|
+
if (!relative || relative === '.') {
|
|
91
|
+
return '';
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return relative.replace(/\\/g, '/') + '/';
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function hashValue(providedHash, content, len) {
|
|
98
|
+
const length = normalizeLength(len);
|
|
99
|
+
if (hasValue(providedHash)) {
|
|
100
|
+
return String(providedHash).slice(0, length);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return getHash(content, length);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function interpolateName(template, vars) {
|
|
107
|
+
const values = vars || {};
|
|
108
|
+
|
|
109
|
+
if (typeof template === 'function') {
|
|
110
|
+
return asString(template(values));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return asString(template).replace(/\[([A-Za-z]+)(?::(\d+))?\]/g, (match, token, len) => {
|
|
114
|
+
switch (token.toLowerCase()) {
|
|
115
|
+
case 'name':
|
|
116
|
+
return derivedName(values);
|
|
117
|
+
case 'ext':
|
|
118
|
+
return derivedExt(values);
|
|
119
|
+
case 'base':
|
|
120
|
+
return derivedBase(values);
|
|
121
|
+
case 'path':
|
|
122
|
+
return relativePath(values);
|
|
123
|
+
case 'query':
|
|
124
|
+
return asString(values.query);
|
|
125
|
+
case 'id':
|
|
126
|
+
return asString(hasValue(values.id) ? values.id : (hasValue(values.chunkName) ? values.chunkName : values.name));
|
|
127
|
+
case 'chunkname':
|
|
128
|
+
return asString(values.chunkName || values.name);
|
|
129
|
+
case 'hash':
|
|
130
|
+
case 'fullhash':
|
|
131
|
+
return hashValue(values.fullHash, values.content, len);
|
|
132
|
+
case 'contenthash':
|
|
133
|
+
case 'chunkhash':
|
|
134
|
+
return hashValue(values.contentHash, values.content, len);
|
|
135
|
+
default:
|
|
136
|
+
return match;
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
module.exports = {
|
|
142
|
+
interpolateName,
|
|
143
|
+
getHash,
|
|
144
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rustwrap/webpack",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "A webpack-compatible Node API and CLI backed by the Rolldown bundler (Rust/Oxc) for fast builds and excellent tree-shaking. Drop-in `webpack` override for pcf-scripts and webpack-based pipelines.",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "node test/run.js"
|
|
11
|
+
},
|
|
12
|
+
"bin": {
|
|
13
|
+
"webpack": "bin/rollpack.js",
|
|
14
|
+
"rollpack": "bin/rollpack.js"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"lib/",
|
|
18
|
+
"bin/",
|
|
19
|
+
"README.md"
|
|
20
|
+
],
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"acorn": "^8.17.0",
|
|
23
|
+
"eslint-scope": "^9.1.2",
|
|
24
|
+
"loader-runner": "^4.3.2",
|
|
25
|
+
"mime-types": "^3.0.2",
|
|
26
|
+
"postcss": "^8.5.16",
|
|
27
|
+
"postcss-modules": "^6.0.1",
|
|
28
|
+
"rolldown": "^1.1.3",
|
|
29
|
+
"schema-utils": "^4.3.3",
|
|
30
|
+
"tapable": "^2.3.3",
|
|
31
|
+
"terser-webpack-plugin": "^5.6.1",
|
|
32
|
+
"webpack-sources": "^3.5.0"
|
|
33
|
+
},
|
|
34
|
+
"keywords": [
|
|
35
|
+
"webpack",
|
|
36
|
+
"rolldown",
|
|
37
|
+
"bundler",
|
|
38
|
+
"pcf",
|
|
39
|
+
"tree-shaking"
|
|
40
|
+
],
|
|
41
|
+
"license": "MIT"
|
|
42
|
+
}
|