@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/compiler.js
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* rollpack Compiler/Compilation — a tapable-based webpack lifecycle so real plugins (apply(compiler))
|
|
4
|
+
* run. The heavy lifting (producing entry bundles) happens in the `make` phase via Rolldown; plugins
|
|
5
|
+
* then add/modify compilation.assets through processAssets/emit hooks before they're written.
|
|
6
|
+
*/
|
|
7
|
+
const path = require("path");
|
|
8
|
+
const fs = require("fs");
|
|
9
|
+
const {
|
|
10
|
+
SyncHook, SyncBailHook, AsyncSeriesHook, AsyncParallelHook, AsyncSeriesBailHook,
|
|
11
|
+
} = require("tapable");
|
|
12
|
+
const sources = require("webpack-sources");
|
|
13
|
+
|
|
14
|
+
const STAGES = {
|
|
15
|
+
PROCESS_ASSETS_STAGE_ADDITIONAL: -2000,
|
|
16
|
+
PROCESS_ASSETS_STAGE_PRE_PROCESS: -1000,
|
|
17
|
+
PROCESS_ASSETS_STAGE_DERIVED: -200,
|
|
18
|
+
PROCESS_ASSETS_STAGE_ADDITIONS: -100,
|
|
19
|
+
PROCESS_ASSETS_STAGE_NONE: 0,
|
|
20
|
+
PROCESS_ASSETS_STAGE_OPTIMIZE: 100,
|
|
21
|
+
PROCESS_ASSETS_STAGE_OPTIMIZE_COUNT: 200,
|
|
22
|
+
PROCESS_ASSETS_STAGE_OPTIMIZE_COMPATIBILITY: 300,
|
|
23
|
+
PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE: 400,
|
|
24
|
+
PROCESS_ASSETS_STAGE_DEV_TOOLING: 500,
|
|
25
|
+
PROCESS_ASSETS_STAGE_OPTIMIZE_INLINE: 700,
|
|
26
|
+
PROCESS_ASSETS_STAGE_SUMMARIZE: 1000,
|
|
27
|
+
PROCESS_ASSETS_STAGE_OPTIMIZE_HASH: 2500,
|
|
28
|
+
PROCESS_ASSETS_STAGE_OPTIMIZE_TRANSFER: 3000,
|
|
29
|
+
PROCESS_ASSETS_STAGE_ANALYSE: 4000,
|
|
30
|
+
PROCESS_ASSETS_STAGE_REPORT: 5000,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
function toSource(s) {
|
|
34
|
+
if (s == null) return new sources.RawSource("");
|
|
35
|
+
if (typeof s === "string" || Buffer.isBuffer(s)) return new sources.RawSource(s);
|
|
36
|
+
if (typeof s.source === "function") return s; // already a Source
|
|
37
|
+
return new sources.RawSource(String(s));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
class Compilation {
|
|
41
|
+
constructor(compiler) {
|
|
42
|
+
this.compiler = compiler;
|
|
43
|
+
this.options = compiler.options;
|
|
44
|
+
this.outputOptions = compiler.options.output || {};
|
|
45
|
+
this.assets = {}; // name -> Source
|
|
46
|
+
this.assetsInfo = new Map(); // name -> info
|
|
47
|
+
this.errors = [];
|
|
48
|
+
this.warnings = [];
|
|
49
|
+
this.chunks = new Set();
|
|
50
|
+
this.modules = new Set();
|
|
51
|
+
this.entrypoints = new Map();
|
|
52
|
+
this.namedChunkGroups = new Map();
|
|
53
|
+
this.hash = null;
|
|
54
|
+
this.fullHash = null;
|
|
55
|
+
this.name = compiler.name;
|
|
56
|
+
const processAssets = new AsyncSeriesHook(["assets"]);
|
|
57
|
+
this.hooks = {
|
|
58
|
+
buildModule: new SyncHook(["module"]),
|
|
59
|
+
succeedModule: new SyncHook(["module"]),
|
|
60
|
+
finishModules: new AsyncSeriesHook(["modules"]),
|
|
61
|
+
seal: new SyncHook([]),
|
|
62
|
+
optimize: new SyncHook([]),
|
|
63
|
+
optimizeModules: new SyncBailHook(["modules"]),
|
|
64
|
+
optimizeChunks: new SyncBailHook(["chunks"]),
|
|
65
|
+
optimizeTree: new AsyncSeriesHook(["chunks", "modules"]),
|
|
66
|
+
optimizeChunkAssets: new AsyncSeriesHook(["chunks"]),
|
|
67
|
+
optimizeAssets: new AsyncSeriesHook(["assets"]),
|
|
68
|
+
afterOptimizeAssets: new SyncHook(["assets"]),
|
|
69
|
+
processAssets,
|
|
70
|
+
afterProcessAssets: new SyncHook(["assets"]),
|
|
71
|
+
additionalAssets: new AsyncSeriesHook([]),
|
|
72
|
+
chunkAsset: new SyncHook(["chunk", "filename"]),
|
|
73
|
+
childCompiler: new SyncHook(["childCompiler", "compilerName", "compilerIndex"]),
|
|
74
|
+
log: new SyncBailHook(["origin", "logEntry"]),
|
|
75
|
+
additionalChunkAssets: new AsyncSeriesHook(["chunks"]),
|
|
76
|
+
needAdditionalSeal: new SyncBailHook([]),
|
|
77
|
+
afterSeal: new AsyncSeriesHook([]),
|
|
78
|
+
};
|
|
79
|
+
// webpack tags processAssets taps with a numeric `stage`; emulate by sorting taps by stage.
|
|
80
|
+
patchStagedHook(processAssets);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
emitAsset(name, source, info) {
|
|
84
|
+
name = name.replace(/\\/g, "/");
|
|
85
|
+
this.assets[name] = toSource(source);
|
|
86
|
+
if (info) this.assetsInfo.set(name, info);
|
|
87
|
+
}
|
|
88
|
+
updateAsset(name, sourceOrFn, info) {
|
|
89
|
+
name = name.replace(/\\/g, "/");
|
|
90
|
+
const cur = this.assets[name];
|
|
91
|
+
this.assets[name] = toSource(typeof sourceOrFn === "function" ? sourceOrFn(cur) : sourceOrFn);
|
|
92
|
+
if (info) {
|
|
93
|
+
const prev = this.assetsInfo.get(name) || {};
|
|
94
|
+
this.assetsInfo.set(name, typeof info === "function" ? info(prev) : Object.assign({}, prev, info));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
getAsset(name) {
|
|
98
|
+
name = name.replace(/\\/g, "/");
|
|
99
|
+
if (!(name in this.assets)) return undefined;
|
|
100
|
+
return { name, source: this.assets[name], info: this.assetsInfo.get(name) || {} };
|
|
101
|
+
}
|
|
102
|
+
deleteAsset(name) { name = name.replace(/\\/g, "/"); delete this.assets[name]; this.assetsInfo.delete(name); }
|
|
103
|
+
renameAsset(oldName, newName) {
|
|
104
|
+
if (this.assets[oldName]) { this.assets[newName] = this.assets[oldName]; this.assetsInfo.set(newName, this.assetsInfo.get(oldName) || {}); this.deleteAsset(oldName); }
|
|
105
|
+
}
|
|
106
|
+
getAssets() { return Object.keys(this.assets).map((name) => ({ name, source: this.assets[name], info: this.assetsInfo.get(name) || {} })); }
|
|
107
|
+
emitError(e) { this.errors.push(e instanceof Error ? e : { message: String(e && e.message || e) }); }
|
|
108
|
+
emitWarning(w) { this.warnings.push(w instanceof Error ? w : { message: String(w && w.message || w) }); }
|
|
109
|
+
getPath(filename, data) { return require("./template").interpolateName(filename, data || {}); }
|
|
110
|
+
getLogger() { const noop = () => {}; return new Proxy({}, { get: () => noop }); }
|
|
111
|
+
getStats() { return require("./stats").createStats(this); }
|
|
112
|
+
}
|
|
113
|
+
Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL = STAGES.PROCESS_ASSETS_STAGE_ADDITIONAL;
|
|
114
|
+
Object.assign(Compilation, STAGES);
|
|
115
|
+
|
|
116
|
+
// Let plugins tap processAssets with { name, stage }; run taps ordered by ascending stage.
|
|
117
|
+
function patchStagedHook(hook) {
|
|
118
|
+
const staged = [];
|
|
119
|
+
const origTap = hook.tap.bind(hook);
|
|
120
|
+
const origTapPromise = hook.tapPromise ? hook.tapPromise.bind(hook) : null;
|
|
121
|
+
const origTapAsync = hook.tapAsync ? hook.tapAsync.bind(hook) : null;
|
|
122
|
+
hook._stagedTaps = staged;
|
|
123
|
+
const register = (opts, fn, kind) => {
|
|
124
|
+
const stage = (typeof opts === "object" && opts.stage) || 0;
|
|
125
|
+
staged.push({ stage, fn, kind, name: (typeof opts === "object" && opts.name) || "plugin" });
|
|
126
|
+
};
|
|
127
|
+
hook.tap = (opts, fn) => register(opts, fn, "sync");
|
|
128
|
+
if (origTapPromise) hook.tapPromise = (opts, fn) => register(opts, fn, "promise");
|
|
129
|
+
if (origTapAsync) hook.tapAsync = (opts, fn) => register(opts, fn, "async");
|
|
130
|
+
hook.callStaged = async (assets) => {
|
|
131
|
+
const ordered = staged.slice().sort((a, b) => a.stage - b.stage);
|
|
132
|
+
for (const t of ordered) {
|
|
133
|
+
if (t.kind === "sync") t.fn(assets);
|
|
134
|
+
else if (t.kind === "promise") await t.fn(assets);
|
|
135
|
+
else await new Promise((res, rej) => t.fn(assets, (e) => (e ? rej(e) : res())));
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
class Compiler {
|
|
141
|
+
constructor(context, options) {
|
|
142
|
+
this.context = context;
|
|
143
|
+
this.options = options || {};
|
|
144
|
+
this.name = this.options.name;
|
|
145
|
+
this.outputPath = (this.options.output && this.options.output.path) || path.join(context, "dist");
|
|
146
|
+
this.watchMode = false;
|
|
147
|
+
this.running = false;
|
|
148
|
+
this.hooks = {
|
|
149
|
+
environment: new SyncHook([]),
|
|
150
|
+
afterEnvironment: new SyncHook([]),
|
|
151
|
+
afterPlugins: new SyncHook(["compiler"]),
|
|
152
|
+
afterResolvers: new SyncHook(["compiler"]),
|
|
153
|
+
initialize: new SyncHook([]),
|
|
154
|
+
beforeRun: new AsyncSeriesHook(["compiler"]),
|
|
155
|
+
run: new AsyncSeriesHook(["compiler"]),
|
|
156
|
+
watchRun: new AsyncSeriesHook(["compiler"]),
|
|
157
|
+
beforeCompile: new AsyncSeriesHook(["params"]),
|
|
158
|
+
compile: new SyncHook(["params"]),
|
|
159
|
+
thisCompilation: new SyncHook(["compilation", "params"]),
|
|
160
|
+
compilation: new SyncHook(["compilation", "params"]),
|
|
161
|
+
make: new AsyncParallelHook(["compilation"]),
|
|
162
|
+
finishMake: new AsyncSeriesHook(["compilation"]),
|
|
163
|
+
afterCompile: new AsyncSeriesHook(["compilation"]),
|
|
164
|
+
shouldEmit: new SyncBailHook(["compilation"]),
|
|
165
|
+
emit: new AsyncSeriesHook(["compilation"]),
|
|
166
|
+
assetEmitted: new AsyncSeriesHook(["file", "info"]),
|
|
167
|
+
afterEmit: new AsyncSeriesHook(["compilation"]),
|
|
168
|
+
done: new AsyncSeriesHook(["stats"]),
|
|
169
|
+
afterDone: new SyncHook(["stats"]),
|
|
170
|
+
failed: new SyncHook(["error"]),
|
|
171
|
+
invalid: new SyncHook(["filename", "changeTime"]),
|
|
172
|
+
watchClose: new SyncHook([]),
|
|
173
|
+
shutdown: new AsyncSeriesHook([]),
|
|
174
|
+
infrastructureLog: new SyncBailHook(["origin", "type", "args"]),
|
|
175
|
+
};
|
|
176
|
+
this.outputFileSystem = fs;
|
|
177
|
+
this.inputFileSystem = fs;
|
|
178
|
+
this.webpack = require("./index.js");
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
getInfrastructureLogger() { const noop = () => {}; return new Proxy({}, { get: () => noop }); }
|
|
182
|
+
|
|
183
|
+
newCompilation(params) {
|
|
184
|
+
const compilation = new Compilation(this);
|
|
185
|
+
this.hooks.thisCompilation.call(compilation, params || {});
|
|
186
|
+
this.hooks.compilation.call(compilation, params || {});
|
|
187
|
+
return compilation;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async run(callback) {
|
|
191
|
+
this.running = true;
|
|
192
|
+
const done = (err, stats) => { this.running = false; callback(err, stats); };
|
|
193
|
+
try {
|
|
194
|
+
await this.hooks.beforeRun.promise(this);
|
|
195
|
+
await this.hooks.run.promise(this);
|
|
196
|
+
const stats = await this.compile();
|
|
197
|
+
await this.hooks.done.promise(stats);
|
|
198
|
+
this.hooks.afterDone.call(stats);
|
|
199
|
+
done(null, stats);
|
|
200
|
+
} catch (err) {
|
|
201
|
+
this.hooks.failed.call(err);
|
|
202
|
+
done(err);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
async compile() {
|
|
207
|
+
const params = {};
|
|
208
|
+
await this.hooks.beforeCompile.promise(params);
|
|
209
|
+
this.hooks.compile.call(params);
|
|
210
|
+
const compilation = this.newCompilation(params);
|
|
211
|
+
// make: produce entry bundles into compilation.assets (Rolldown), see build.runMake.
|
|
212
|
+
await this.hooks.make.promise(compilation);
|
|
213
|
+
await this.hooks.finishMake.promise(compilation);
|
|
214
|
+
await this.hooks.afterCompile.promise(compilation);
|
|
215
|
+
// seal-ish: run processAssets stages so plugins can add/transform assets.
|
|
216
|
+
compilation.hooks.seal.call();
|
|
217
|
+
await compilation.hooks.processAssets.callStaged(compilation.assets);
|
|
218
|
+
compilation.hooks.afterProcessAssets.call(compilation.assets);
|
|
219
|
+
await compilation.hooks.optimizeAssets.promise(compilation.assets);
|
|
220
|
+
compilation.hooks.afterOptimizeAssets.call(compilation.assets);
|
|
221
|
+
// emit
|
|
222
|
+
if (this.hooks.shouldEmit.call(compilation) !== false) {
|
|
223
|
+
await this.hooks.emit.promise(compilation);
|
|
224
|
+
await this.emitAssets(compilation);
|
|
225
|
+
await this.hooks.afterEmit.promise(compilation);
|
|
226
|
+
}
|
|
227
|
+
return compilation.getStats();
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
async emitAssets(compilation) {
|
|
231
|
+
const outDir = this.outputPath;
|
|
232
|
+
if (this.options.output && this.options.output.clean) {
|
|
233
|
+
try { fs.rmSync(outDir, { recursive: true, force: true }); } catch (_) {}
|
|
234
|
+
}
|
|
235
|
+
for (const name of Object.keys(compilation.assets)) {
|
|
236
|
+
const source = compilation.assets[name];
|
|
237
|
+
const target = path.join(outDir, name);
|
|
238
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
239
|
+
const content = source.source();
|
|
240
|
+
fs.writeFileSync(target, content);
|
|
241
|
+
await this.hooks.assetEmitted.promise(name, { content: Buffer.isBuffer(content) ? content : Buffer.from(String(content)), targetPath: target, compilation });
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
watch(watchOptions, handler) {
|
|
246
|
+
this.watchMode = true;
|
|
247
|
+
const root = this.context;
|
|
248
|
+
let timer = null, building = false;
|
|
249
|
+
const run = () => {
|
|
250
|
+
building = true;
|
|
251
|
+
this.hooks.watchRun.promise(this)
|
|
252
|
+
.then(() => this.compile())
|
|
253
|
+
.then((stats) => this.hooks.done.promise(stats).then(() => { building = false; handler(null, stats); }))
|
|
254
|
+
.catch((e) => { building = false; this.hooks.failed.call(e); handler(e); });
|
|
255
|
+
};
|
|
256
|
+
run();
|
|
257
|
+
let watcher;
|
|
258
|
+
try {
|
|
259
|
+
watcher = fs.watch(root, { recursive: true }, (_ev, f) => {
|
|
260
|
+
if (f && /node_modules|[\\/](out|dist)[\\/]|\.d\.ts$/.test(f)) return;
|
|
261
|
+
if (building) return;
|
|
262
|
+
this.hooks.invalid.call(f, Date.now());
|
|
263
|
+
clearTimeout(timer); timer = setTimeout(run, (watchOptions && watchOptions.aggregateTimeout) || 200);
|
|
264
|
+
});
|
|
265
|
+
} catch (_) {}
|
|
266
|
+
return { close: (cb) => { clearTimeout(timer); if (watcher) watcher.close(); this.hooks.watchClose.call(); cb && cb(); }, invalidate: () => run() };
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
close(cb) { this.hooks.shutdown.promise().then(() => cb && cb(), (e) => cb && cb(e)); }
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
class MultiCompiler {
|
|
273
|
+
constructor(compilers) {
|
|
274
|
+
this.compilers = compilers;
|
|
275
|
+
this.hooks = { done: new SyncHook(["stats"]), invalid: new SyncHook([]), run: new SyncHook(["compiler"]), watchClose: new SyncHook([]), watchRun: new SyncHook(["compiler"]) };
|
|
276
|
+
}
|
|
277
|
+
run(callback) {
|
|
278
|
+
const allStats = [];
|
|
279
|
+
let i = 0;
|
|
280
|
+
const next = () => {
|
|
281
|
+
if (i >= this.compilers.length) {
|
|
282
|
+
const multi = makeMultiStats(allStats);
|
|
283
|
+
this.hooks.done.call(multi);
|
|
284
|
+
return callback(null, multi);
|
|
285
|
+
}
|
|
286
|
+
this.compilers[i++].run((err, stats) => { if (err) return callback(err); allStats.push(stats); next(); });
|
|
287
|
+
};
|
|
288
|
+
next();
|
|
289
|
+
}
|
|
290
|
+
watch(watchOptions, handler) {
|
|
291
|
+
const watchers = this.compilers.map((c) => c.watch(watchOptions, (err, stats) => handler(err, stats)));
|
|
292
|
+
return { close: (cb) => { let n = watchers.length; if (!n) return cb && cb(); watchers.forEach((w) => w.close(() => { if (--n === 0) cb && cb(); })); } };
|
|
293
|
+
}
|
|
294
|
+
close(cb) { let n = this.compilers.length; if (!n) return cb && cb(); this.compilers.forEach((c) => c.close(() => { if (--n === 0) cb && cb(); })); }
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function makeMultiStats(statsArr) {
|
|
298
|
+
return {
|
|
299
|
+
stats: statsArr,
|
|
300
|
+
hasErrors: () => statsArr.some((s) => s.hasErrors()),
|
|
301
|
+
hasWarnings: () => statsArr.some((s) => s.hasWarnings()),
|
|
302
|
+
toJson: (o) => ({ children: statsArr.map((s) => s.toJson(o)) }),
|
|
303
|
+
toString: (o) => statsArr.map((s) => s.toString(o)).join("\n\n"),
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
module.exports = { Compiler, Compilation, MultiCompiler, sources, STAGES, toSource };
|
package/lib/config.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* Shared webpack-config translation helpers (entry, output/library, externals, resolve, define). */
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
|
|
6
|
+
function normalizeEntries(cfg, context) {
|
|
7
|
+
const entry = cfg.entry;
|
|
8
|
+
const out = cfg.output || {};
|
|
9
|
+
const format = libraryFormat(out);
|
|
10
|
+
const nested = (name) => (format === "iife" || format === "umd") ? !!(name && name.includes(".")) : false;
|
|
11
|
+
const resolveInput = (imp) => {
|
|
12
|
+
const v = Array.isArray(imp) ? imp[imp.length - 1] : imp;
|
|
13
|
+
return path.isAbsolute(v) ? v : path.resolve(context, v);
|
|
14
|
+
};
|
|
15
|
+
if (!entry || typeof entry === "string" || Array.isArray(entry)) {
|
|
16
|
+
const ln = libraryName(out.library, "main");
|
|
17
|
+
return [{ name: "main", input: resolveInput(entry || "./src/index.js"), filename: out.filename || "main.js", libraryName: ln, format, extend: nested(ln) }];
|
|
18
|
+
}
|
|
19
|
+
const list = [];
|
|
20
|
+
for (const [name, v] of Object.entries(entry)) {
|
|
21
|
+
let imp = v, filename;
|
|
22
|
+
if (v && typeof v === "object" && !Array.isArray(v)) { imp = Array.isArray(v.import) ? v.import[v.import.length - 1] : v.import; filename = v.filename; }
|
|
23
|
+
const ln = libraryName(out.library, name);
|
|
24
|
+
list.push({ name, input: resolveInput(imp), filename: (filename || out.filename || `${name}.js`).replace(/\[name\]/g, name), libraryName: ln, format, extend: nested(ln) });
|
|
25
|
+
}
|
|
26
|
+
return list;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function libraryFormat(out) {
|
|
30
|
+
const lib = out.library;
|
|
31
|
+
const type = out.libraryTarget || (lib && !Array.isArray(lib) && typeof lib === "object" && lib.type);
|
|
32
|
+
switch (type) {
|
|
33
|
+
case "commonjs": case "commonjs2": case "commonjs-module": return "cjs";
|
|
34
|
+
case "module": return "es";
|
|
35
|
+
case "umd": case "umd2": return "umd";
|
|
36
|
+
case "amd": case "amd-require": return "amd";
|
|
37
|
+
case "global": case "var": case "window": case "self": case "assign": case "this": default: return lib ? "iife" : "iife";
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function libraryName(lib, entryName) {
|
|
42
|
+
if (!lib) return undefined;
|
|
43
|
+
if (Array.isArray(lib)) return lib.map((s) => String(s).replace(/\[name\]/g, entryName)).join(".");
|
|
44
|
+
if (typeof lib === "string") return lib.replace(/\[name\]/g, entryName);
|
|
45
|
+
if (lib && lib.name) return (Array.isArray(lib.name) ? lib.name.join(".") : String(lib.name)).replace(/\[name\]/g, entryName);
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function findTsconfig(dir) {
|
|
50
|
+
for (let i = 0; i < 10 && dir; i++) {
|
|
51
|
+
const f = path.join(dir, "tsconfig.json");
|
|
52
|
+
if (fs.existsSync(f)) return f;
|
|
53
|
+
const up = path.dirname(dir);
|
|
54
|
+
if (up === dir) break;
|
|
55
|
+
dir = up;
|
|
56
|
+
}
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function buildResolve(cfg, context) {
|
|
61
|
+
const r = cfg.resolve || {};
|
|
62
|
+
const resolve = {};
|
|
63
|
+
if (r.alias) { resolve.alias = {}; for (const [k, v] of Object.entries(r.alias)) resolve.alias[k] = v === false ? [require.resolve("./empty-module.js")] : (Array.isArray(v) ? v : [v]); }
|
|
64
|
+
if (r.extensions && r.extensions.length) resolve.extensions = r.extensions;
|
|
65
|
+
if (r.mainFields) resolve.mainFields = r.mainFields;
|
|
66
|
+
if (r.mainFiles) resolve.mainFiles = r.mainFiles;
|
|
67
|
+
if (r.conditionNames) resolve.conditionNames = r.conditionNames;
|
|
68
|
+
if (r.modules) resolve.modules = r.modules;
|
|
69
|
+
if (r.symlinks === false) resolve.symlinks = false;
|
|
70
|
+
if (r.extensionAlias) resolve.extensionAlias = r.extensionAlias;
|
|
71
|
+
// resolve.fallback: map `false` entries to an empty module, drop polyfill paths onto alias.
|
|
72
|
+
if (r.fallback) {
|
|
73
|
+
resolve.alias = resolve.alias || {};
|
|
74
|
+
for (const [k, v] of Object.entries(r.fallback)) resolve.alias[k] = v === false ? [require.resolve("./empty-module.js")] : [v];
|
|
75
|
+
}
|
|
76
|
+
const ts = findTsconfig(context);
|
|
77
|
+
if (ts) resolve.tsconfigFilename = ts;
|
|
78
|
+
return resolve;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function stripGlobalPrefix(s) { return String(s).replace(/^(var|window|global|commonjs2?|this|self|umd|amd|module|node-commonjs|import|script|promise|system|jsonp)\s+/, ""); }
|
|
82
|
+
function sanitizeGlobal(id) { return String(id).replace(/[^a-zA-Z0-9_$]/g, "_"); }
|
|
83
|
+
|
|
84
|
+
function buildExternals(cfg, context) {
|
|
85
|
+
const list = Array.isArray(cfg.externals) ? cfg.externals : cfg.externals ? [cfg.externals] : [];
|
|
86
|
+
const map = {}; const regexes = []; const fns = [];
|
|
87
|
+
for (const e of list) {
|
|
88
|
+
if (!e) continue;
|
|
89
|
+
if (e instanceof RegExp) regexes.push(e);
|
|
90
|
+
else if (typeof e === "function") fns.push(e);
|
|
91
|
+
else if (typeof e === "object") {
|
|
92
|
+
for (const [k, v] of Object.entries(e)) {
|
|
93
|
+
if (v instanceof RegExp) regexes.push(v);
|
|
94
|
+
else if (typeof v === "string") map[k] = stripGlobalPrefix(v);
|
|
95
|
+
else if (Array.isArray(v)) map[k] = stripGlobalPrefix(String(v[0]));
|
|
96
|
+
else if (v === true) map[k] = k;
|
|
97
|
+
else if (v && typeof v === "object" && v.root) map[k] = Array.isArray(v.root) ? v.root.join(".") : String(v.root);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const callFn = (request) => {
|
|
102
|
+
for (const fn of fns) {
|
|
103
|
+
let result;
|
|
104
|
+
try {
|
|
105
|
+
if (fn.length >= 3) fn({ request, context }, request, (_e, r) => { result = r; });
|
|
106
|
+
else { const ret = fn({ request, context }, (_e, r) => { result = r; }); if (ret && typeof ret.then !== "function" && result === undefined) result = ret; }
|
|
107
|
+
} catch (_) {}
|
|
108
|
+
if (result) return typeof result === "string" ? stripGlobalPrefix(result) : (Array.isArray(result) ? result.join(".") : String(result));
|
|
109
|
+
}
|
|
110
|
+
return undefined;
|
|
111
|
+
};
|
|
112
|
+
const resolveGlobal = (id) => {
|
|
113
|
+
if (map[id]) return map[id];
|
|
114
|
+
for (const k of Object.keys(map)) if (id === k || id.startsWith(k + "/")) return map[k];
|
|
115
|
+
const f = callFn(id); if (f) return f;
|
|
116
|
+
return undefined;
|
|
117
|
+
};
|
|
118
|
+
const isExternal = (id) => {
|
|
119
|
+
if (id == null) return false;
|
|
120
|
+
if (resolveGlobal(id) !== undefined) return true;
|
|
121
|
+
for (const re of regexes) if (re.test(id)) return true;
|
|
122
|
+
return false;
|
|
123
|
+
};
|
|
124
|
+
const globals = (id) => resolveGlobal(id) || sanitizeGlobal(id);
|
|
125
|
+
return { isExternal, globals };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function buildDefine(cfg, prod, rollpackDefine) {
|
|
129
|
+
const def = Object.assign({ "process.env.NODE_ENV": JSON.stringify(prod ? "production" : "development") }, rollpackDefine || {});
|
|
130
|
+
return def;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
module.exports = { normalizeEntries, libraryFormat, libraryName, findTsconfig, buildResolve, buildExternals, buildDefine, sanitizeGlobal, stripGlobalPrefix };
|
package/lib/css.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Native CSS pipeline (webpack's css-loader/style-loader emit webpack-runtime-coupled output that a
|
|
4
|
+
* non-webpack bundler can't consume, so rollpack handles CSS itself, Vite-style):
|
|
5
|
+
* - .scss/.sass -> compiled with the consumer's `sass` (or node-sass) if available.
|
|
6
|
+
* - .less -> compiled with the consumer's `less` if available.
|
|
7
|
+
* - .css -> used as-is.
|
|
8
|
+
* Then either injected at runtime via a <style> tag (style-loader behavior) or, when
|
|
9
|
+
* MiniCssExtractPlugin is in use, emitted as a .css asset.
|
|
10
|
+
*
|
|
11
|
+
* CSS Modules (*.module.css) get a best-effort local-class identity map (className -> className).
|
|
12
|
+
*/
|
|
13
|
+
const path = require("path");
|
|
14
|
+
const fs = require("fs");
|
|
15
|
+
|
|
16
|
+
function resolveFrom(name, dirs) {
|
|
17
|
+
for (const d of dirs) { try { return require(require.resolve(name, { paths: [d] })); } catch (_) {} }
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function compile(resource, context, compilation) {
|
|
22
|
+
const ext = path.extname(resource).toLowerCase();
|
|
23
|
+
const dirs = [path.dirname(resource), context, process.cwd()];
|
|
24
|
+
try {
|
|
25
|
+
if (ext === ".scss" || ext === ".sass") {
|
|
26
|
+
const sass = resolveFrom("sass", dirs);
|
|
27
|
+
if (sass && sass.compile) return sass.compile(resource, { style: "compressed", loadPaths: [path.dirname(resource)] }).css;
|
|
28
|
+
const nodeSass = resolveFrom("node-sass", dirs);
|
|
29
|
+
if (nodeSass && nodeSass.renderSync) return nodeSass.renderSync({ file: resource, outputStyle: "compressed" }).css.toString();
|
|
30
|
+
compilation && compilation.warnings.push({ message: `rollpack: no 'sass' available to compile ${path.basename(resource)} — emitting empty CSS` });
|
|
31
|
+
return "";
|
|
32
|
+
}
|
|
33
|
+
if (ext === ".less") {
|
|
34
|
+
const less = resolveFrom("less", dirs);
|
|
35
|
+
if (less && less.render) { let css = ""; less.render(fs.readFileSync(resource, "utf8"), { filename: resource, compress: true }, (e, o) => { if (!e && o) css = o.css; }); return css; }
|
|
36
|
+
return "";
|
|
37
|
+
}
|
|
38
|
+
return fs.readFileSync(resource, "utf8");
|
|
39
|
+
} catch (e) {
|
|
40
|
+
compilation && compilation.errors.push({ message: `rollpack CSS (${path.basename(resource)}): ${e && e.message || e}` });
|
|
41
|
+
return "";
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Very small CSS-modules local map: collect class names so `styles.foo` resolves to "foo".
|
|
46
|
+
function moduleMap(css) {
|
|
47
|
+
const names = new Set();
|
|
48
|
+
const re = /\.(-?[_a-zA-Z][_a-zA-Z0-9-]*)/g;
|
|
49
|
+
let m;
|
|
50
|
+
while ((m = re.exec(css))) names.add(m[1]);
|
|
51
|
+
const obj = {};
|
|
52
|
+
for (const n of names) obj[n] = n;
|
|
53
|
+
return obj;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Proper CSS Modules scoping via postcss + postcss-modules: rewrites local class names to scoped
|
|
57
|
+
// names and returns the { localName: scopedName } export map (composes supported).
|
|
58
|
+
async function runCssModules(css, resource, prod) {
|
|
59
|
+
let postcss, postcssModules;
|
|
60
|
+
try { postcss = require("postcss"); postcssModules = require("postcss-modules"); }
|
|
61
|
+
catch (_) { return { css, tokens: moduleMap(css) }; } // fallback: identity map
|
|
62
|
+
let tokens = {};
|
|
63
|
+
const scoped = prod ? "[hash:base64:8]" : "[name]__[local]___[hash:base64:5]";
|
|
64
|
+
try {
|
|
65
|
+
const result = await postcss([
|
|
66
|
+
postcssModules({ generateScopedName: scoped, getJSON: (_f, json) => { tokens = json; } }),
|
|
67
|
+
]).process(css, { from: resource });
|
|
68
|
+
return { css: result.css, tokens };
|
|
69
|
+
} catch (e) {
|
|
70
|
+
return { css, tokens: moduleMap(css) };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function handleCss(resource, cfg, compilation, prod, context, extract) {
|
|
75
|
+
const isModule = /\.module\.(css|scss|sass|less)$/i.test(resource);
|
|
76
|
+
let css = compile(resource, context, compilation) || "";
|
|
77
|
+
let exportsObj = {};
|
|
78
|
+
if (isModule && css) {
|
|
79
|
+
const r = await runCssModules(css, resource, prod);
|
|
80
|
+
css = r.css;
|
|
81
|
+
exportsObj = r.tokens || {};
|
|
82
|
+
}
|
|
83
|
+
const exportDefault = `export default ${JSON.stringify(exportsObj)};` +
|
|
84
|
+
Object.keys(exportsObj).filter((k) => /^[A-Za-z_$][\w$]*$/.test(k)).map((k) => `\nexport var ${k} = ${JSON.stringify(exportsObj[k])};`).join("");
|
|
85
|
+
|
|
86
|
+
if (extract) {
|
|
87
|
+
const out = cfg.output || {};
|
|
88
|
+
const base = path.basename(resource).replace(/\.(scss|sass|less)$/i, ".css");
|
|
89
|
+
const name = (out.cssFilename || "[name].css").replace(/\[name\]/g, path.basename(base, ".css"));
|
|
90
|
+
if (compilation) compilation.emitAsset(name.replace(/^\.?[\\/]/, ""), css);
|
|
91
|
+
return { code: exportDefault, moduleType: "js" };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const inject = `(function(){if(typeof document==='undefined')return;var c=${JSON.stringify(css)};if(!c)return;var s=document.createElement('style');s.setAttribute('data-rollpack','');s.appendChild(document.createTextNode(c));document.head.appendChild(s);})();`;
|
|
95
|
+
return { code: `${inject}\n${exportDefault}`, moduleType: "js" };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function cssExtractEnabled(cfg) {
|
|
99
|
+
for (const p of cfg.plugins || []) if (p && p.constructor && p.constructor.name === "MiniCssExtractPlugin") return true;
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
module.exports = { handleCss, cssExtractEnabled };
|