@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.
@@ -0,0 +1,176 @@
1
+ "use strict";
2
+ /*
3
+ * rollpack dev server — a webpack-dev-server-shaped dev server over the rollpack Compiler.
4
+ *
5
+ * It serves the compiled assets (+ static dirs) over HTTP, watches sources and rebuilds via the
6
+ * Compiler, and pushes updates to the browser over Server-Sent Events. The injected client either
7
+ * triggers a fast full reload (live-reload) or, when `hot` is enabled, runs registered
8
+ * `module.hot` dispose handlers first. Granular state-preserving HMR is not possible on a
9
+ * whole-bundle engine, so hot updates fall back to a reload (documented).
10
+ *
11
+ * Constructor is compatible with `new WebpackDevServer(options, compiler)` (and the legacy
12
+ * `(compiler, options)` order).
13
+ */
14
+ const http = require("http");
15
+ const fs = require("fs");
16
+ const path = require("path");
17
+
18
+ const MIME = {
19
+ ".html": "text/html", ".js": "application/javascript", ".mjs": "application/javascript",
20
+ ".css": "text/css", ".json": "application/json", ".map": "application/json", ".svg": "image/svg+xml",
21
+ ".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".gif": "image/gif",
22
+ ".webp": "image/webp", ".ico": "image/x-icon", ".woff": "font/woff", ".woff2": "font/woff2",
23
+ ".ttf": "font/ttf", ".wasm": "application/wasm", ".txt": "text/plain",
24
+ };
25
+ function mime(file) { return MIME[path.extname(file).toLowerCase()] || "application/octet-stream"; }
26
+
27
+ // Browser client: connects SSE, applies hot dispose handlers, then reloads on each successful build.
28
+ const CLIENT = `(function(){
29
+ if (typeof window === "undefined" || !window.EventSource) return;
30
+ var hot = window.__rollpack_hot__ || (window.__rollpack_hot__ = (function(){
31
+ var accepts = [], disposes = [], statusHandlers = [], status = "idle", data = {};
32
+ function setStatus(s){ status = s; statusHandlers.forEach(function(h){ try { h(s); } catch(e){} }); }
33
+ return {
34
+ _accepts: accepts, _disposes: disposes,
35
+ accept: function(dep, cb){ if (typeof dep === "function" || dep == null) { accepts.push(dep || function(){}); } else { accepts.push(cb || function(){}); } },
36
+ decline: function(){}, dispose: function(cb){ disposes.push(cb); }, addDisposeHandler: function(cb){ disposes.push(cb); },
37
+ removeDisposeHandler: function(){}, invalidate: function(){ location.reload(); },
38
+ data: data, status: function(){ return status; }, addStatusHandler: function(cb){ statusHandlers.push(cb); }, removeStatusHandler: function(){},
39
+ apply: function(){ return Promise.resolve([]); }, check: function(){ return Promise.resolve(null); }, _setStatus: setStatus,
40
+ };
41
+ })());
42
+ var first = true;
43
+ var es = new EventSource("/__rollpack_sse");
44
+ es.addEventListener("message", function(ev){
45
+ var msg; try { msg = JSON.parse(ev.data); } catch(e){ return; }
46
+ if (msg.type === "connected") { first = false; return; }
47
+ if (msg.type === "errors") { console.error("%c[rollpack] build failed", "color:red", "\\n" + (msg.errors||[]).join("\\n")); return; }
48
+ if (msg.type === "ok") {
49
+ hot._setStatus("check");
50
+ try { hot._disposes.forEach(function(cb){ try { cb(hot.data); } catch(e){} }); } catch(e){}
51
+ console.log("[rollpack] update — reloading");
52
+ hot._setStatus("apply");
53
+ location.reload();
54
+ }
55
+ });
56
+ es.addEventListener("error", function(){ /* EventSource auto-retries */ });
57
+ })();`;
58
+
59
+ function normalizeStatic(stat, context) {
60
+ if (stat === false) return [];
61
+ if (stat == null) return [path.join(context, "public"), context];
62
+ const arr = Array.isArray(stat) ? stat : [stat];
63
+ return arr.map((s) => {
64
+ if (typeof s === "string") return path.isAbsolute(s) ? s : path.resolve(context, s);
65
+ if (s && s.directory) return path.isAbsolute(s.directory) ? s.directory : path.resolve(context, s.directory);
66
+ return context;
67
+ });
68
+ }
69
+
70
+ function injectClient(html) {
71
+ const tag = `<script src="/__rollpack_hmr_client.js"></script>`;
72
+ if (/<\/body>/i.test(html)) return html.replace(/<\/body>/i, tag + "</body>");
73
+ if (/<\/head>/i.test(html)) return html.replace(/<\/head>/i, tag + "</head>");
74
+ return html + "\n" + tag;
75
+ }
76
+
77
+ class DevServer {
78
+ constructor(options, compiler) {
79
+ // Support both `new DevServer(options, compiler)` and legacy `(compiler, options)`.
80
+ if (options && (typeof options.run === "function" || options.hooks)) { const t = options; options = compiler; compiler = t; }
81
+ this.options = options || {};
82
+ this.compiler = compiler;
83
+ this.sseClients = new Set();
84
+ this.server = null;
85
+ this.watching = null;
86
+ this.lastHash = "";
87
+ }
88
+
89
+ start(cb) {
90
+ const o = this.options;
91
+ const compiler = this.compiler;
92
+ const port = o.port != null ? o.port : 8080;
93
+ const host = o.host || "localhost";
94
+ const context = compiler.context;
95
+ const ctx = {
96
+ outDir: compiler.outputPath,
97
+ staticDirs: normalizeStatic(o.static, context),
98
+ historyApiFallback: o.historyApiFallback,
99
+ };
100
+ // Enable hot defines for the build.
101
+ if (o.hot !== false) { compiler.$rollpack = compiler.$rollpack || {}; compiler.$rollpack.hot = true; }
102
+
103
+ this.server = http.createServer((req, res) => this.handle(req, res, ctx));
104
+ return new Promise((resolve) => {
105
+ this.server.listen(port, host, () => {
106
+ const actualPort = (this.server.address() && this.server.address().port) || port;
107
+ const url = `http://${host === "0.0.0.0" ? "localhost" : host}:${actualPort}/`;
108
+ console.log(`\x1b[36m\x1b[1mrollpack\x1b[0m dev server running at \x1b[33m${url}\x1b[0m`);
109
+ // Build + watch, push updates to clients.
110
+ this.watching = compiler.watch(compiler.options.watchOptions || {}, (err, stats) => {
111
+ if (err) { console.error(err); return; }
112
+ this.lastHash = (stats && stats.toJson && stats.toJson().hash) || String(Date.now());
113
+ this.broadcast(stats);
114
+ });
115
+ if (cb) cb(null, this);
116
+ resolve(this);
117
+ });
118
+ });
119
+ }
120
+
121
+ broadcast(stats) {
122
+ const hasErrors = stats && stats.hasErrors && stats.hasErrors();
123
+ const payload = JSON.stringify(hasErrors
124
+ ? { type: "errors", hash: this.lastHash, errors: (stats.toJson().errors || []).map((e) => e.message) }
125
+ : { type: "ok", hash: this.lastHash });
126
+ for (const res of this.sseClients) { try { res.write(`data: ${payload}\n\n`); } catch (_) {} }
127
+ }
128
+
129
+ handle(req, res, ctx) {
130
+ const url = decodeURIComponent((req.url || "/").split("?")[0]);
131
+ if (url === "/__rollpack_sse") return this.sse(res);
132
+ if (url === "/__rollpack_hmr_client.js") { res.writeHead(200, { "Content-Type": "application/javascript", "Cache-Control": "no-cache" }); return res.end(CLIENT); }
133
+ const rel = url.replace(/^\/+/, "") || "index.html";
134
+ const bases = [ctx.outDir, ...ctx.staticDirs];
135
+ for (const b of bases) if (this.serveFile(path.join(b, rel), res)) return;
136
+ // SPA history fallback to index.html for extension-less routes.
137
+ if (ctx.historyApiFallback !== false && !path.extname(rel)) {
138
+ for (const b of bases) if (this.serveFile(path.join(b, "index.html"), res)) return;
139
+ }
140
+ res.writeHead(404, { "Content-Type": "text/plain" });
141
+ res.end("rollpack dev server: not found — " + url);
142
+ }
143
+
144
+ serveFile(file, res) {
145
+ try {
146
+ if (!fs.existsSync(file) || !fs.statSync(file).isFile()) return false;
147
+ const type = mime(file);
148
+ let body = fs.readFileSync(file);
149
+ if (type === "text/html") body = Buffer.from(injectClient(body.toString("utf8")));
150
+ res.writeHead(200, { "Content-Type": type, "Cache-Control": "no-cache" });
151
+ res.end(body);
152
+ return true;
153
+ } catch (_) { return false; }
154
+ }
155
+
156
+ sse(res) {
157
+ res.writeHead(200, { "Content-Type": "text/event-stream", "Cache-Control": "no-cache", Connection: "keep-alive", "Access-Control-Allow-Origin": "*" });
158
+ res.write("retry: 1000\n\n");
159
+ res.write(`data: ${JSON.stringify({ type: "connected" })}\n\n`);
160
+ this.sseClients.add(res);
161
+ res.on("close", () => this.sseClients.delete(res));
162
+ }
163
+
164
+ // webpack-dev-server v4 API
165
+ startCallback(cb) { this.start().then(() => cb && cb(), cb); }
166
+ stopCallback(cb) { this.stop().then(() => cb && cb(), cb); }
167
+ async stop() {
168
+ if (this.watching) await new Promise((r) => this.watching.close(r));
169
+ for (const r of this.sseClients) { try { r.end(); } catch (_) {} }
170
+ this.sseClients.clear();
171
+ if (this.server) await new Promise((r) => this.server.close(r));
172
+ }
173
+ close(cb) { this.stop().then(() => cb && cb(), cb); }
174
+ }
175
+
176
+ module.exports = DevServer;
@@ -0,0 +1,2 @@
1
+ // Empty module used for `resolve.fallback[x] = false`, IgnorePlugin, and null-loader equivalents.
2
+ module.exports = {};
package/lib/index.js ADDED
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ /*
3
+ * rollpack — a webpack-compatible Node API and CLI backed by the Rolldown bundler.
4
+ *
5
+ * This is the public entry: the `webpack(options, callback)` factory, the Compiler/Compilation
6
+ * lifecycle (tapable hooks, so real plugins run), and the full `webpack.*` namespace. The actual
7
+ * bundling + tree-shaking is done by Rolldown (see build.js); the rest of this package translates
8
+ * the webpack config/API surface.
9
+ */
10
+ const crypto = require("crypto");
11
+ const { Compiler, Compilation, MultiCompiler, sources } = require("./compiler");
12
+ const { runMake } = require("./build");
13
+ const plugins = require("./plugins");
14
+
15
+ function webpack(options, callback) {
16
+ if (typeof options === "function") options = options(process.env, {}) || {};
17
+ let compiler;
18
+ if (Array.isArray(options)) compiler = new MultiCompiler(options.map((o) => createCompiler(o || {})));
19
+ else compiler = createCompiler(options || {});
20
+ if (typeof callback === "function") {
21
+ const watch = Array.isArray(options) ? options.some((o) => o && o.watch) : options.watch;
22
+ if (watch) {
23
+ const wo = Array.isArray(options) ? (options[0].watchOptions || {}) : (options.watchOptions || {});
24
+ return compiler.watch(wo, callback);
25
+ }
26
+ compiler.run(callback);
27
+ return compiler;
28
+ }
29
+ return compiler;
30
+ }
31
+
32
+ function createCompiler(options) {
33
+ const context = options.context || process.cwd();
34
+ const compiler = new Compiler(context, options);
35
+ compiler.$rollpack = { define: {}, provide: {}, ignore: [], normalReplace: [] };
36
+ compiler.hooks.environment.call();
37
+ compiler.hooks.afterEnvironment.call();
38
+
39
+ // Apply user plugins (real apply(compiler) — taps hooks / populates $rollpack).
40
+ for (const p of options.plugins || []) {
41
+ try {
42
+ if (p && typeof p.apply === "function") p.apply(compiler);
43
+ else if (typeof p === "function") p.call(compiler, compiler);
44
+ } catch (e) { /* a plugin that needs deep webpack internals — keep building */ }
45
+ }
46
+ compiler.hooks.afterPlugins.call(compiler);
47
+ compiler.hooks.afterResolvers.call(compiler);
48
+
49
+ // The make phase: Rolldown build -> compilation.assets.
50
+ compiler.hooks.make.tapPromise("rollpack", (compilation) => runMake(compilation, options, context));
51
+
52
+ // After assets are produced: performance hints + ignoreWarnings (before Stats is created).
53
+ compiler.hooks.afterEmit.tapPromise("rollpack:post", async (compilation) => {
54
+ applyPerformance(options, compilation);
55
+ filterWarnings(options, compilation);
56
+ });
57
+
58
+ // Default console summary (unless stats are silenced).
59
+ compiler.hooks.done.tapPromise("rollpack:summary", async (stats) => {
60
+ const quiet = options.stats === false || options.stats === "none" || options.stats === "errors-only"
61
+ || (options.infrastructureLogging && (options.infrastructureLogging.level === "none" || options.infrastructureLogging.level === "error"));
62
+ if (!quiet) printSummary(stats);
63
+ });
64
+
65
+ return compiler;
66
+ }
67
+
68
+ function applyPerformance(options, compilation) {
69
+ const perf = options.performance;
70
+ if (!perf || perf.hints === false) return;
71
+ const max = perf.maxAssetSize || 250000;
72
+ for (const name of Object.keys(compilation.assets)) {
73
+ if (!/\.(js|mjs|cjs|css)$/.test(name)) continue;
74
+ const size = bytes(compilation.assets[name].source());
75
+ if (size > max) {
76
+ const msg = `asset ${name} (${(size / 1024) | 0} KiB) exceeds the recommended size limit (${(max / 1024) | 0} KiB)`;
77
+ (perf.hints === "error" ? compilation.errors : compilation.warnings).push({ message: msg });
78
+ }
79
+ }
80
+ }
81
+
82
+ function filterWarnings(options, compilation) {
83
+ const ig = options.ignoreWarnings;
84
+ if (!ig || !ig.length) return;
85
+ compilation.warnings = compilation.warnings.filter((w) => !ig.some((rule) =>
86
+ rule instanceof RegExp ? rule.test(w.message || "") : (typeof rule === "function" ? rule(w, compilation) : false)));
87
+ }
88
+
89
+ function bytes(c) { return Buffer.isBuffer(c) ? c.length : Buffer.byteLength(String(c), "utf8"); }
90
+ function fmtSize(b) { return b > 1048576 ? (b / 1048576).toFixed(2) + " MiB" : (b / 1024).toFixed(1) + " KiB"; }
91
+ function fmtTime(ms) { return ms >= 1000 ? (ms / 1000).toFixed(2) + "s" : ms + "ms"; }
92
+ const C = (process.stdout.isTTY || process.env.FORCE_COLOR) ? { d: "\x1b[2m", b: "\x1b[1m", g: "\x1b[32m", c: "\x1b[36m", y: "\x1b[33m", m: "\x1b[35m", r: "\x1b[0m" } : { d: "", b: "", g: "", c: "", y: "", m: "", r: "" };
93
+ function printSummary(stats) {
94
+ const j = stats.toJson();
95
+ const total = (j.assets || []).reduce((s, a) => s + a.size, 0);
96
+ for (const e of j.errors || []) console.log(`${C.y}ERROR${C.r} ${e.message}`);
97
+ for (const w of j.warnings || []) console.log(`${C.y}WARNING${C.r} ${w.message}`);
98
+ console.log(`${C.c}${C.b}rollpack${C.r} ${C.g}${(j.assets || []).length} assets${C.r} ${C.m}${fmtSize(total)}${C.r} ${C.d}via rolldown in${C.r} ${C.y}${fmtTime(j.time || 0)}${C.r}`);
99
+ for (const a of j.assets || []) console.log(` ${C.d}asset${C.r} ${C.c}${a.name}${C.r} ${C.m}${fmtSize(a.size)}${C.r}`);
100
+ }
101
+
102
+ // ---------------------------------------------------------------------------------------------
103
+ // Public namespace (webpack.*)
104
+ // ---------------------------------------------------------------------------------------------
105
+ class WebpackError extends Error { constructor(msg) { super(msg); this.name = "WebpackError"; } }
106
+
107
+ webpack.webpack = webpack;
108
+ webpack.Compiler = Compiler;
109
+ webpack.Compilation = Compilation;
110
+ webpack.MultiCompiler = MultiCompiler;
111
+ webpack.sources = sources;
112
+ webpack.WebpackError = WebpackError;
113
+ webpack.version = require("../package.json").version;
114
+ webpack.util = {
115
+ createHash: (algo) => {
116
+ const norm = (algo === "xxhash64" || algo === "md4") ? (crypto.getHashes().includes("md4") ? "md4" : "sha256") : (algo || "sha256");
117
+ try { return crypto.createHash(norm); } catch (_) { return crypto.createHash("sha256"); }
118
+ },
119
+ };
120
+ webpack.ModuleFilenameHelpers = {
121
+ matchPart: (str, test) => test == null ? true : (test instanceof RegExp ? test.test(str) : (typeof test === "string" ? str.includes(test) : !!test)),
122
+ matchObject: (obj, str) => {
123
+ if (!obj) return true;
124
+ if (obj.test && !webpack.ModuleFilenameHelpers.matchPart(str, obj.test)) return false;
125
+ if (obj.include && !webpack.ModuleFilenameHelpers.matchPart(str, obj.include)) return false;
126
+ if (obj.exclude && webpack.ModuleFilenameHelpers.matchPart(str, obj.exclude)) return false;
127
+ return true;
128
+ },
129
+ };
130
+ webpack.RuntimeGlobals = {};
131
+ webpack.DevServer = require("./dev-server.js");
132
+
133
+ // Built-in plugins
134
+ Object.assign(webpack, {
135
+ DefinePlugin: plugins.DefinePlugin,
136
+ EnvironmentPlugin: plugins.EnvironmentPlugin,
137
+ ProvidePlugin: plugins.ProvidePlugin,
138
+ BannerPlugin: plugins.BannerPlugin,
139
+ IgnorePlugin: plugins.IgnorePlugin,
140
+ NormalModuleReplacementPlugin: plugins.NormalModuleReplacementPlugin,
141
+ ContextReplacementPlugin: plugins.ContextReplacementPlugin,
142
+ SourceMapDevToolPlugin: plugins.SourceMapDevToolPlugin,
143
+ EvalSourceMapDevToolPlugin: plugins.EvalSourceMapDevToolPlugin,
144
+ ProgressPlugin: plugins.ProgressPlugin,
145
+ LoaderOptionsPlugin: plugins.LoaderOptionsPlugin,
146
+ HotModuleReplacementPlugin: plugins.HotModuleReplacementPlugin,
147
+ WatchIgnorePlugin: plugins.WatchIgnorePlugin,
148
+ DllPlugin: plugins.DllPlugin,
149
+ DllReferencePlugin: plugins.DllReferencePlugin,
150
+ HashedModuleIdsPlugin: plugins.HashedModuleIdsPlugin,
151
+ NamedModulesPlugin: plugins.NamedModulesPlugin,
152
+ NamedChunksPlugin: plugins.NamedChunksPlugin,
153
+ NoEmitOnErrorsPlugin: plugins.NoEmitOnErrorsPlugin,
154
+ });
155
+ webpack.optimize = plugins.optimize;
156
+ webpack.container = plugins.container;
157
+ webpack.sharing = {};
158
+ webpack.web = {};
159
+ webpack.node = {};
160
+ webpack.ids = { HashedModuleIdsPlugin: plugins.HashedModuleIdsPlugin };
161
+
162
+ module.exports = webpack;
package/lib/loaders.js ADDED
@@ -0,0 +1,211 @@
1
+ "use strict";
2
+ /*
3
+ * rollpack loader system — runs real webpack loader chains (module.rules) via loader-runner, so
4
+ * css-loader/style-loader/sass-loader/@svgr/raw-loader/url-loader/file-loader/custom loaders work.
5
+ *
6
+ * JS/TS/JSX transpilation is left to Rolldown/Oxc (faster, equivalent output), so the well-known
7
+ * transpile-only loaders (ts-loader, babel-loader, swc-loader, esbuild-loader) are filtered OUT of
8
+ * chains; everything else runs. A file is processed by this system only when it has a non-empty
9
+ * remaining loader chain.
10
+ */
11
+ const path = require("path");
12
+ const fs = require("fs");
13
+ const { runLoaders } = require("loader-runner");
14
+
15
+ const SKIP_LOADERS = /[\\/](ts-loader|babel-loader|swc-loader|esbuild-loader|@swc[\\/]loader|style-loader|css-loader|sass-loader|less-loader|postcss-loader|mini-css-extract-plugin)[\\/]/i;
16
+ const JS_EXT = /\.(jsx?|mjs|cjs|tsx?|mts|cts)$/i;
17
+
18
+ // Flatten module.rules into pre/normal/post buckets, resolving `oneOf` and nested `rules`.
19
+ function flattenRules(rules, out) {
20
+ for (const r of rules || []) {
21
+ if (!r) continue;
22
+ if (r.oneOf) { out._oneOf = out._oneOf || []; out._oneOf.push(r.oneOf); }
23
+ flattenRule(r, out);
24
+ if (r.rules) flattenRules(r.rules, out);
25
+ }
26
+ return out;
27
+ }
28
+ function flattenRule(r, out) {
29
+ if (!r || (!r.test && !r.resource && !r.include && !r.exclude && !r.use && !r.loader && !r.resourceQuery)) return;
30
+ const bucket = r.enforce === "pre" ? out.pre : r.enforce === "post" ? out.post : out.normal;
31
+ bucket.push(r);
32
+ }
33
+
34
+ function ruleMatches(rule, resource, query) {
35
+ const cond = (c, val) => {
36
+ if (c == null) return undefined;
37
+ if (c instanceof RegExp) return c.test(val);
38
+ if (typeof c === "string") return val.startsWith(c) || val === c;
39
+ if (typeof c === "function") return !!c(val);
40
+ if (Array.isArray(c)) return c.some((x) => cond(x, val) === true);
41
+ if (typeof c === "object") {
42
+ if (c.and) return c.and.every((x) => cond(x, val) === true);
43
+ if (c.or) return c.or.some((x) => cond(x, val) === true);
44
+ if (c.not) return !cond(c.not, val);
45
+ return undefined;
46
+ }
47
+ return undefined;
48
+ };
49
+ const test = rule.test !== undefined ? cond(rule.test, resource) : (rule.resource !== undefined ? cond(rule.resource, resource) : undefined);
50
+ if (test === false) return false;
51
+ if (rule.include !== undefined && cond(rule.include, resource) !== true) return false;
52
+ if (rule.exclude !== undefined && cond(rule.exclude, resource) === true) return false;
53
+ if (rule.resourceQuery !== undefined && cond(rule.resourceQuery, query || "") !== true) return false;
54
+ // a rule with no positive resource condition but include/query still counts only if something matched
55
+ if (test === undefined && rule.include === undefined && rule.resourceQuery === undefined) return false;
56
+ return true;
57
+ }
58
+
59
+ // Normalize a rule's `use`/`loader` into [{loader, options, ident}], in declared order.
60
+ function ruleUse(rule) {
61
+ let use = rule.use || rule.loader || rule.loaders;
62
+ if (!use) return [];
63
+ if (!Array.isArray(use)) use = [use];
64
+ return use.map((u) => {
65
+ if (typeof u === "string") return { loader: u, options: rule.options };
66
+ if (typeof u === "function") return { loader: "__inline_fn__", fn: u };
67
+ return { loader: u.loader, options: u.options, ident: u.ident };
68
+ }).filter((u) => u.loader);
69
+ }
70
+
71
+ function resolveLoader(name, contexts) {
72
+ if (path.isAbsolute(name) && fs.existsSync(name)) return name;
73
+ for (const base of contexts) {
74
+ try { return require.resolve(name, { paths: [base] }); } catch (_) {}
75
+ try { return require.resolve(name + "/package.json", { paths: [base] }).replace(/package\.json$/, "index.js"); } catch (_) {}
76
+ }
77
+ return null;
78
+ }
79
+
80
+ // Build the ordered loader list (post + normal + pre) for a resource, filtering transpile loaders.
81
+ function loadersFor(resource, query, buckets, contexts) {
82
+ const collect = (bucketRules) => {
83
+ const acc = [];
84
+ for (const rule of bucketRules) {
85
+ if (!ruleMatches(rule, resource, query)) continue;
86
+ if (rule.type && /^asset/.test(rule.type)) { acc._assetType = rule.type; acc._parser = rule.parser; acc._generator = rule.generator; }
87
+ for (const u of ruleUse(rule)) acc.push(u);
88
+ }
89
+ return acc;
90
+ };
91
+ // oneOf: first matching sub-rule wins
92
+ let oneOfUse = [];
93
+ let assetMeta = null;
94
+ for (const group of buckets._oneOf || []) {
95
+ for (const rule of group) {
96
+ if (ruleMatches(rule, resource, query)) {
97
+ if (rule.type && /^asset/.test(rule.type)) assetMeta = { type: rule.type, parser: rule.parser, generator: rule.generator };
98
+ oneOfUse = ruleUse(rule);
99
+ break;
100
+ }
101
+ }
102
+ if (oneOfUse.length || assetMeta) break;
103
+ }
104
+ const normal = collect(buckets.normal).concat(oneOfUse);
105
+ const pre = collect(buckets.pre);
106
+ const post = collect(buckets.post);
107
+ if (normal._assetType && !assetMeta) assetMeta = { type: normal._assetType, parser: normal._parser, generator: normal._generator };
108
+ // webpack order for runLoaders: [post, normal, pre] (normal phase runs right->left, so pre first)
109
+ let chain = post.concat(normal).concat(pre);
110
+ // resolve + filter transpile-only loaders
111
+ chain = chain
112
+ .map((u) => {
113
+ if (u.fn) return { loader: "inline", options: u.options, normal: u.fn, pitch: u.fn.pitch };
114
+ const p = resolveLoader(u.loader, contexts);
115
+ return p ? { loader: p, options: u.options, ident: u.ident } : null;
116
+ })
117
+ .filter((u) => u && !(typeof u.loader === "string" && SKIP_LOADERS.test(u.loader)));
118
+ return { chain, assetMeta };
119
+ }
120
+
121
+ /*
122
+ * A Rolldown plugin that applies module.rules. For any resolved module whose extension is non-JS or
123
+ * which has a non-empty (non-transpile) loader chain, it runs the chain and returns the JS result.
124
+ */
125
+ function loaderPlugin(cfg, context, compilation) {
126
+ const buckets = flattenRules((cfg.module && cfg.module.rules) || [], { pre: [], normal: [], post: [] });
127
+ const contexts = [context, process.cwd()];
128
+ const prod = cfg.mode !== "development";
129
+ const cssExtract = require("./css").cssExtractEnabled(cfg);
130
+ const hasRules = buckets.pre.length || buckets.normal.length || buckets.post.length || (buckets._oneOf && buckets._oneOf.length);
131
+ return {
132
+ name: "rollpack:loaders",
133
+ async load(id) {
134
+ const [resource, query] = id.split("?");
135
+ // Native CSS pipeline, independent of configured css/style loaders.
136
+ if (/\.(css|scss|sass|less)$/i.test(resource)) {
137
+ return require("./css").handleCss(resource, cfg, compilation, prod, context, cssExtract);
138
+ }
139
+ if (!hasRules) return null;
140
+ const { chain, assetMeta } = loadersFor(resource, query, buckets, contexts);
141
+ const isJs = JS_EXT.test(resource);
142
+ if (!chain.length && !assetMeta) {
143
+ if (isJs) return null; // let Oxc handle JS/TS natively
144
+ // Non-JS file with no configured loader: emit as an asset/resource (webpack-5-like default)
145
+ // so the build doesn't choke parsing it as JS.
146
+ return require("./assets").handleAsset(resource, { type: "asset/resource" }, cfg, compilation, prod);
147
+ }
148
+ // Asset module handling (type: asset/*) takes precedence when no JS-producing loaders remain.
149
+ if (assetMeta && !chain.length) {
150
+ return require("./assets").handleAsset(resource, assetMeta, cfg, compilation, prod);
151
+ }
152
+ if (!chain.length) return null;
153
+ const source = fs.readFileSync(resource);
154
+ const result = await runChain(chain, resource, source, cfg, context, compilation, prod);
155
+ return result;
156
+ },
157
+ };
158
+ }
159
+
160
+ function runChain(chain, resource, source, cfg, context, compilation, prod) {
161
+ return new Promise((resolve, reject) => {
162
+ runLoaders({
163
+ resource,
164
+ loaders: chain,
165
+ context: makeLoaderContext(cfg, context, compilation, prod, resource),
166
+ readResource: (_p, cb) => cb(null, source),
167
+ }, (err, res) => {
168
+ if (err) return reject(err);
169
+ let code = res.result && res.result[0];
170
+ if (code == null) return resolve({ code: "export default undefined;", moduleType: "js" });
171
+ if (Buffer.isBuffer(code)) code = code.toString("utf8");
172
+ const map = res.result && res.result[1];
173
+ resolve({ code: String(code), map: map && typeof map === "object" ? map : null, moduleType: "js" });
174
+ });
175
+ });
176
+ }
177
+
178
+ // A reasonable webpack NormalModule loaderContext.
179
+ function makeLoaderContext(cfg, context, compilation, prod, resource) {
180
+ const dir = path.dirname(resource);
181
+ return {
182
+ rootContext: context,
183
+ context: dir,
184
+ resourcePath: resource,
185
+ resourceQuery: "",
186
+ mode: prod ? "production" : "development",
187
+ sourceMap: !!cfg.devtool,
188
+ target: cfg.target || "web",
189
+ hot: false,
190
+ webpack: true,
191
+ _compiler: compilation && compilation.compiler,
192
+ _compilation: compilation,
193
+ _module: { type: "javascript/auto", resource },
194
+ getOptions(schema) { return (this.__options) || {}; },
195
+ emitWarning(w) { compilation && compilation.warnings.push({ message: String(w && w.message || w) }); },
196
+ emitError(e) { compilation && compilation.errors.push({ message: String(e && e.message || e) }); },
197
+ emitFile(name, content, map, assetInfo) { compilation && compilation.emitAsset(name, content, assetInfo); },
198
+ addDependency() {}, dependency() {}, addContextDependency() {}, addMissingDependency() {}, clearDependencies() {},
199
+ getLogger() { const noop = () => {}; return new Proxy({}, { get: () => noop }); },
200
+ resolve(ctx, request, cb) { try { cb(null, require.resolve(request, { paths: [ctx] })); } catch (e) { cb(e); } },
201
+ getResolve() { return (ctx, request, cb) => { try { const p = require.resolve(request, { paths: [ctx] }); return cb ? cb(null, p) : Promise.resolve(p); } catch (e) { return cb ? cb(e) : Promise.reject(e); } }; },
202
+ utils: {
203
+ absolutify: (ctxt, p) => path.resolve(ctxt, p),
204
+ contextify: (ctxt, p) => path.relative(ctxt, p).replace(/\\/g, "/"),
205
+ createHash: () => require("crypto").createHash("md4" in require("crypto").getHashes() ? "md4" : "sha256"),
206
+ },
207
+ fs,
208
+ };
209
+ }
210
+
211
+ module.exports = { loaderPlugin, flattenRules, ruleMatches, loadersFor };