@kirana-style/webpack 0.1.0 → 0.2.0
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/CHANGELOG.md +47 -0
- package/LICENSE +21 -0
- package/README.md +1 -1
- package/package.json +8 -3
- package/src/index.d.ts +52 -51
- package/src/index.js +94 -105
- package/src/loader.d.ts +10 -8
- package/src/loader.js +41 -49
- package/src/next.d.ts +7 -6
- package/src/next.js +19 -14
- package/src/session.d.ts +32 -36
- package/src/session.js +49 -43
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.2.0](https://github.com/kirana-style/kirana/compare/v0.1.0...v0.2.0) (2026-10-15)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### ⚠ BREAKING CHANGES
|
|
7
|
+
|
|
8
|
+
* one command name, kirana-style ([#29](https://github.com/kirana-style/kirana/issues/29))
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
* **editor:** real editor output on the site, open vsx trusted publishing ([#21](https://github.com/kirana-style/kirana/issues/21)) ([350fa4e](https://github.com/kirana-style/kirana/commit/350fa4ec0d8054a082d6c7dcdae2b5be53f8d98a))
|
|
13
|
+
* one command name, kirana-style ([#29](https://github.com/kirana-style/kirana/issues/29)) ([b3f3154](https://github.com/kirana-style/kirana/commit/b3f3154662589dd1bd43fd0ff2341acf4f3df628))
|
|
14
|
+
* **site:** paper, ink, scenery and type for one identity ([#27](https://github.com/kirana-style/kirana/issues/27)) ([5da3c6f](https://github.com/kirana-style/kirana/commit/5da3c6f0f1c8cbfdb450b36a6609a3ab4b20e358))
|
|
15
|
+
* **site:** reorganise the homepage, product pages and docs ([#28](https://github.com/kirana-style/kirana/issues/28)) ([88b5209](https://github.com/kirana-style/kirana/commit/88b52093488b2aa0112b458ca04b836c83d03954))
|
|
16
|
+
* **site:** scenery gradients, logo downloads, pixel k, glass icons ([#25](https://github.com/kirana-style/kirana/issues/25)) ([2953dc1](https://github.com/kirana-style/kirana/commit/2953dc126f47b68257ebfdb33c61992984708c49))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Bug fixes
|
|
20
|
+
|
|
21
|
+
* hold emnapi at 2.0.0-alpha.6, the wasi engine fails on the beta ([#26](https://github.com/kirana-style/kirana/issues/26)) ([8aa33e1](https://github.com/kirana-style/kirana/commit/8aa33e1dbccaefa15b87f6487ac0a346bbf6581a))
|
|
22
|
+
* settle the ember dev check, resolve code scanning findings ([#23](https://github.com/kirana-style/kirana/issues/23)) ([0c266c8](https://github.com/kirana-style/kirana/commit/0c266c8428c1453892beeeb5f98918cbc0eae6ff))
|
|
23
|
+
* **site:** keep syntax colours in the production build ([#22](https://github.com/kirana-style/kirana/issues/22)) ([621f2fc](https://github.com/kirana-style/kirana/commit/621f2fcf67dada773ca66110e295ab7ac5605f56))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
### Documentation
|
|
27
|
+
|
|
28
|
+
* fix the extension's settings table ([#13](https://github.com/kirana-style/kirana/issues/13)) ([457e06d](https://github.com/kirana-style/kirana/commit/457e06d12f9e3b005e0820aab36faac5bf3f80b3))
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
### Dependencies
|
|
32
|
+
|
|
33
|
+
* bump the minor-and-patch group across 1 directory with 3 updates ([#19](https://github.com/kirana-style/kirana/issues/19)) ([7ea00ed](https://github.com/kirana-style/kirana/commit/7ea00edcc5cc02b9ab5e41b13f152ae344ea448f))
|
|
34
|
+
* emnapi 2.0.0-beta.1, minor and patch updates ([#24](https://github.com/kirana-style/kirana/issues/24)) ([a399fa7](https://github.com/kirana-style/kirana/commit/a399fa78e53dcfd7f41f249ccee1133809e66544))
|
|
35
|
+
|
|
36
|
+
## [0.1.0](https://github.com/kirana-style/kirana/compare/v0.1.0...v0.1.0) (2026-10-13)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
### Features
|
|
40
|
+
|
|
41
|
+
* kirana goes public — write objects, read classes, ship css ([79732ed](https://github.com/kirana-style/kirana/commit/79732edd5cab419169ab74ad59e1c70053dfa57d))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
### Dependencies
|
|
45
|
+
|
|
46
|
+
* bump the minor-and-patch group in /packages/kirana with 6 updates ([#10](https://github.com/kirana-style/kirana/issues/10)) ([0deaf9f](https://github.com/kirana-style/kirana/commit/0deaf9f3e75ebc377d764c294250bd2577d53844))
|
|
47
|
+
* bump the oxc group in /packages/kirana with 7 updates ([#9](https://github.com/kirana-style/kirana/issues/9)) ([a3ca94c](https://github.com/kirana-style/kirana/commit/a3ca94c170b2ca49c9691abf5ad48c3ef4ac8620))
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kirana authors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ export default withKirana({})
|
|
|
23
23
|
- **Loader.** The plugin registers a `pre` loader for scripts, so `sx` is read before `swc-loader`,
|
|
24
24
|
`babel-loader` or Next.js compile JSX away.
|
|
25
25
|
- **Stylesheet.** `@kirana-style/core/stylesheet.css` is ordinary CSS to webpack. The plugin writes the
|
|
26
|
-
finished stylesheet into the emitted asset at `processAssets`' optimize stage
|
|
26
|
+
finished stylesheet into the emitted asset at `processAssets`' optimize stage: after every module,
|
|
27
27
|
before the CSS minimizer and before `realContentHash` renames the file by its content.
|
|
28
28
|
- **Several compilers.** Every compiler of a project (Next.js's server, edge and client) shares one
|
|
29
29
|
compiler session, so atoms from server components reach the client's stylesheet.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kirana-style/webpack",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Kirana for webpack 5 and Rspack: a loader that compiles modules and a plugin that finishes the stylesheet.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "The Kirana authors",
|
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
"url": "https://github.com/kirana-style/kirana/issues"
|
|
15
15
|
},
|
|
16
16
|
"type": "module",
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
17
20
|
"exports": {
|
|
18
21
|
".": {
|
|
19
22
|
"types": "./src/index.d.ts",
|
|
@@ -30,8 +33,8 @@
|
|
|
30
33
|
"./package.json": "./package.json"
|
|
31
34
|
},
|
|
32
35
|
"dependencies": {
|
|
33
|
-
"@kirana-style/compiler": "0.
|
|
34
|
-
"@kirana-style/core": "0.
|
|
36
|
+
"@kirana-style/compiler": "0.2.0",
|
|
37
|
+
"@kirana-style/core": "0.2.0"
|
|
35
38
|
},
|
|
36
39
|
"peerDependencies": {
|
|
37
40
|
"webpack": "^5.90.0",
|
|
@@ -51,6 +54,8 @@
|
|
|
51
54
|
"*.d.ts",
|
|
52
55
|
"*.css",
|
|
53
56
|
"README.md",
|
|
57
|
+
"CHANGELOG.md",
|
|
58
|
+
"LICENSE",
|
|
54
59
|
"builders.json",
|
|
55
60
|
"schemas",
|
|
56
61
|
"gatsby-node.mjs",
|
package/src/index.d.ts
CHANGED
|
@@ -1,64 +1,65 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import { KiranaWebpackOptions } from "./session.js";
|
|
2
|
+
//#region src/index.d.ts
|
|
3
3
|
type Asset = {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
name: string;
|
|
5
|
+
source: {
|
|
6
|
+
source: () => string | Buffer;
|
|
7
|
+
};
|
|
8
8
|
};
|
|
9
9
|
type Compilation = {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
};
|
|
10
|
+
warnings: Error[];
|
|
11
|
+
errors: Error[];
|
|
12
|
+
getAssets: () => readonly Asset[];
|
|
13
|
+
updateAsset: (name: string, source: unknown) => void;
|
|
14
|
+
hooks: {
|
|
15
|
+
finishModules: {
|
|
16
|
+
tapPromise: (name: string, hook: (modules: Iterable<unknown>) => Promise<void>) => void;
|
|
17
|
+
};
|
|
18
|
+
processAssets: {
|
|
19
|
+
tapPromise: (options: {
|
|
20
|
+
name: string;
|
|
21
|
+
stage: number;
|
|
22
|
+
}, hook: () => Promise<void>) => void;
|
|
24
23
|
};
|
|
24
|
+
};
|
|
25
25
|
};
|
|
26
26
|
/** The part of webpack's and Rspack's compiler the plugin uses. */
|
|
27
27
|
export type Compiler = {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
context: string;
|
|
29
|
+
options: {
|
|
30
|
+
mode?: string;
|
|
31
|
+
module: {
|
|
32
|
+
rules: unknown[];
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
webpack: {
|
|
36
|
+
WebpackError: new (message: string) => Error;
|
|
37
|
+
Compilation: {
|
|
38
|
+
PROCESS_ASSETS_STAGE_OPTIMIZE: number;
|
|
39
|
+
};
|
|
40
|
+
sources: {
|
|
41
|
+
RawSource: new (source: string) => unknown;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
hooks: {
|
|
45
|
+
thisCompilation: {
|
|
46
|
+
tap: (name: string, hook: (compilation: Compilation) => void) => void;
|
|
47
|
+
};
|
|
48
|
+
invalid: {
|
|
49
|
+
tap: (name: string, hook: (file: string | null) => void) => void;
|
|
34
50
|
};
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
Compilation: {
|
|
38
|
-
PROCESS_ASSETS_STAGE_OPTIMIZE: number;
|
|
39
|
-
};
|
|
40
|
-
sources: {
|
|
41
|
-
RawSource: new (source: string) => unknown;
|
|
42
|
-
};
|
|
51
|
+
watchRun: {
|
|
52
|
+
tapPromise: (name: string, hook: () => Promise<void>) => void;
|
|
43
53
|
};
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
tap: (name: string, hook: (compilation: Compilation) => void) => void;
|
|
47
|
-
};
|
|
48
|
-
invalid: {
|
|
49
|
-
tap: (name: string, hook: (file: string | null) => void) => void;
|
|
50
|
-
};
|
|
51
|
-
watchRun: {
|
|
52
|
-
tapPromise: (name: string, hook: () => Promise<void>) => void;
|
|
53
|
-
};
|
|
54
|
-
done: {
|
|
55
|
-
tapPromise: (name: string, hook: () => Promise<void>) => void;
|
|
56
|
-
};
|
|
54
|
+
done: {
|
|
55
|
+
tapPromise: (name: string, hook: () => Promise<void>) => void;
|
|
57
56
|
};
|
|
57
|
+
};
|
|
58
58
|
};
|
|
59
59
|
export declare class KiranaPlugin {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
readonly options: KiranaWebpackOptions;
|
|
61
|
+
constructor(options?: KiranaWebpackOptions);
|
|
62
|
+
apply(compiler: Compiler): void;
|
|
63
63
|
}
|
|
64
|
-
|
|
64
|
+
//#endregion
|
|
65
|
+
export { KiranaPlugin as default, type KiranaWebpackOptions };
|
package/src/index.js
CHANGED
|
@@ -1,114 +1,103 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
* and the plugin finishes the stylesheet entry. Rspack implements webpack's plugin and loader API,
|
|
4
|
-
* so one adapter serves both. It never interprets styles (D-028).
|
|
5
|
-
*
|
|
6
|
-
* The stylesheet entry is ordinary CSS to the host — native CSS, `css-loader` with
|
|
7
|
-
* `mini-css-extract-plugin`, Rsbuild's or Next.js's pipeline — so the host names and links it as it
|
|
8
|
-
* does any stylesheet. The loader answers it with the placeholder rule, and the plugin writes the
|
|
9
|
-
* finished stylesheet into the emitted asset at `processAssets`' optimize stage: after every module
|
|
10
|
-
* is built, before the CSS minimizer, and before `realContentHash` renames the file by its real
|
|
11
|
-
* content (on by default in production in both bundlers).
|
|
12
|
-
*
|
|
13
|
-
* Not `rebuildModule` at `finishModules`, which would let the host hash the right content from the
|
|
14
|
-
* start: Rspack 2 panics ("should have event sender") rebuilding a module under Rsbuild's CSS
|
|
15
|
-
* extraction.
|
|
16
|
-
*/
|
|
17
|
-
import { fillStylesheet, shouldCompile, stylesheetPath, } from "@kirana-style/compiler/host";
|
|
1
|
+
import { createSession, sessions } from "./session.js";
|
|
2
|
+
import { fillStylesheet, shouldCompile, stylesheetPath } from "@kirana-style/compiler/host";
|
|
18
3
|
import { createHash } from "node:crypto";
|
|
19
4
|
import { readFile, writeFile } from "node:fs/promises";
|
|
20
5
|
import { tmpdir } from "node:os";
|
|
21
6
|
import path from "node:path";
|
|
22
7
|
import { fileURLToPath } from "node:url";
|
|
23
|
-
|
|
8
|
+
//#region src/index.ts
|
|
9
|
+
/**
|
|
10
|
+
* The webpack 5 and Rspack host adapter (KRN-INT-001, KRN-INT-003): a `pre` loader compiles modules,
|
|
11
|
+
* and the plugin finishes the stylesheet entry. Rspack implements webpack's plugin and loader API,
|
|
12
|
+
* so one adapter serves both. It never interprets styles (D-028).
|
|
13
|
+
*
|
|
14
|
+
* The stylesheet entry is ordinary CSS to the host — native CSS, `css-loader` with
|
|
15
|
+
* `mini-css-extract-plugin`, Rsbuild's or Next.js's pipeline — so the host names and links it as it
|
|
16
|
+
* does any stylesheet. The loader answers it with the placeholder rule, and the plugin writes the
|
|
17
|
+
* finished stylesheet into the emitted asset at `processAssets`' optimize stage: after every module
|
|
18
|
+
* is built, before the CSS minimizer, and before `realContentHash` renames the file by its real
|
|
19
|
+
* content (on by default in production in both bundlers).
|
|
20
|
+
*
|
|
21
|
+
* Not `rebuildModule` at `finishModules`, which would let the host hash the right content from the
|
|
22
|
+
* start: Rspack 2 panics ("should have event sender") rebuilding a module under Rsbuild's CSS
|
|
23
|
+
* extraction.
|
|
24
|
+
*/
|
|
24
25
|
/** The loader, next to this file with the same extension (TypeScript source in the workspace, JavaScript when packed). */
|
|
25
26
|
const LOADER = fileURLToPath(new URL(`./loader${import.meta.url.slice(import.meta.url.lastIndexOf("."))}`, import.meta.url));
|
|
26
27
|
const NAME = "kirana";
|
|
27
28
|
const SCRIPT_FILE = /\.[cm]?[jt]sx?$/;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
for (const asset of compilation.getAssets()) {
|
|
104
|
-
if (!asset.name.endsWith(".css"))
|
|
105
|
-
continue;
|
|
106
|
-
const source = fillStylesheet(String(asset.source.source()), css);
|
|
107
|
-
if (source !== undefined)
|
|
108
|
-
compilation.updateAsset(asset.name, new sources.RawSource(source));
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
export default KiranaPlugin;
|
|
29
|
+
var KiranaPlugin = class {
|
|
30
|
+
options;
|
|
31
|
+
constructor(options = {}) {
|
|
32
|
+
this.options = options;
|
|
33
|
+
}
|
|
34
|
+
apply(compiler) {
|
|
35
|
+
const root = this.options.root ?? compiler.context;
|
|
36
|
+
const stylesheetFile = stylesheetPath(root);
|
|
37
|
+
const id = createSession(this.options, root, stylesheetFile, compiler.options.mode !== "development");
|
|
38
|
+
const session = sessions.get(id);
|
|
39
|
+
const loader = {
|
|
40
|
+
loader: this.options.loader ?? LOADER,
|
|
41
|
+
options: { session: id }
|
|
42
|
+
};
|
|
43
|
+
compiler.options.module.rules.unshift({
|
|
44
|
+
enforce: "pre",
|
|
45
|
+
test: SCRIPT_FILE,
|
|
46
|
+
use: [loader]
|
|
47
|
+
}, {
|
|
48
|
+
enforce: "pre",
|
|
49
|
+
test: (file) => file === stylesheetFile,
|
|
50
|
+
use: [loader]
|
|
51
|
+
});
|
|
52
|
+
compiler.hooks.invalid.tap(NAME, (file) => {
|
|
53
|
+
if (file) session.driver().then((driver) => driver.invalidate(file));
|
|
54
|
+
});
|
|
55
|
+
compiler.hooks.watchRun.tapPromise(NAME, async () => {
|
|
56
|
+
if (session.live) return;
|
|
57
|
+
session.live = path.join(tmpdir(), `kirana-${createHash("sha256").update(root).digest("hex").slice(0, 12)}.css`);
|
|
58
|
+
await writeFile(session.live, "");
|
|
59
|
+
});
|
|
60
|
+
compiler.hooks.done.tapPromise(NAME, async () => {
|
|
61
|
+
if (!session.live) return;
|
|
62
|
+
const css = (await session.driver()).stylesheet(false);
|
|
63
|
+
if (await readFile(session.live, "utf8") !== css) await writeFile(session.live, css);
|
|
64
|
+
});
|
|
65
|
+
compiler.hooks.thisCompilation.tap(NAME, (compilation) => {
|
|
66
|
+
const { Compilation, sources, WebpackError } = compiler.webpack;
|
|
67
|
+
compilation.hooks.finishModules.tapPromise(NAME, async (modules) => {
|
|
68
|
+
const driver = await session.driver();
|
|
69
|
+
for (const module of modules) {
|
|
70
|
+
const file = String(module.resource).split("?")[0];
|
|
71
|
+
if (!SCRIPT_FILE.test(file) || session.compiled.has(file)) continue;
|
|
72
|
+
const source = await readFile(file, "utf8");
|
|
73
|
+
if (!shouldCompile(file, source, driver.libraries)) continue;
|
|
74
|
+
driver.transform(file, source);
|
|
75
|
+
session.compiled.add(file);
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
session.reporter.project({
|
|
79
|
+
warn: (message) => compilation.warnings.push(new WebpackError(message)),
|
|
80
|
+
error: (message) => {
|
|
81
|
+
throw new WebpackError(message);
|
|
82
|
+
}
|
|
83
|
+
}, root, driver.diagnostics());
|
|
84
|
+
} catch (error) {
|
|
85
|
+
compilation.errors.push(error);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
compilation.hooks.processAssets.tapPromise({
|
|
89
|
+
name: NAME,
|
|
90
|
+
stage: Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE
|
|
91
|
+
}, async () => {
|
|
92
|
+
const css = (await session.driver()).stylesheet(session.minify);
|
|
93
|
+
for (const asset of compilation.getAssets()) {
|
|
94
|
+
if (!asset.name.endsWith(".css")) continue;
|
|
95
|
+
const source = fillStylesheet(String(asset.source.source()), css);
|
|
96
|
+
if (source !== void 0) compilation.updateAsset(asset.name, new sources.RawSource(source));
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
//#endregion
|
|
103
|
+
export { KiranaPlugin, KiranaPlugin as default };
|
package/src/loader.d.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
//#region src/loader.d.ts
|
|
1
2
|
/** The part of webpack's and Rspack's loader context the loader uses. */
|
|
2
3
|
export type LoaderContext = {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
resourcePath: string;
|
|
5
|
+
resourceQuery: string;
|
|
6
|
+
getOptions: () => {
|
|
7
|
+
session: string;
|
|
8
|
+
};
|
|
9
|
+
async: () => (error: Error | null, code?: string, map?: unknown) => void;
|
|
10
|
+
addDependency: (file: string) => void;
|
|
11
|
+
emitWarning: (warning: Error) => void;
|
|
11
12
|
};
|
|
12
13
|
export default function kiranaLoader(this: LoaderContext, source: string, map?: unknown): void;
|
|
14
|
+
//#endregion
|
package/src/loader.js
CHANGED
|
@@ -1,51 +1,43 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The loader half of the webpack and Rspack adapter (KRN-INT-001): it compiles one module, or
|
|
3
|
-
* answers the stylesheet entry with the placeholder rule the plugin later replaces. The plugin
|
|
4
|
-
* registers it as a `pre` loader, so it sees the source before any other loader strips types or JSX.
|
|
5
|
-
*/
|
|
6
|
-
import { PLACEHOLDER, shouldCompile } from "@kirana-style/compiler/host";
|
|
7
1
|
import { sessions } from "./session.js";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
else
|
|
48
|
-
callback(null, result.code, result.map && JSON.parse(result.map));
|
|
49
|
-
})
|
|
50
|
-
.catch((error) => callback(error));
|
|
2
|
+
import { PLACEHOLDER, shouldCompile } from "@kirana-style/compiler/host";
|
|
3
|
+
//#region src/loader.ts
|
|
4
|
+
/**
|
|
5
|
+
* The loader half of the webpack and Rspack adapter (KRN-INT-001): it compiles one module, or
|
|
6
|
+
* answers the stylesheet entry with the placeholder rule the plugin later replaces. The plugin
|
|
7
|
+
* registers it as a `pre` loader, so it sees the source before any other loader strips types or JSX.
|
|
8
|
+
*/
|
|
9
|
+
function kiranaLoader(source, map) {
|
|
10
|
+
const callback = this.async();
|
|
11
|
+
const session = sessions.get(this.getOptions().session);
|
|
12
|
+
if (!session) {
|
|
13
|
+
callback(/* @__PURE__ */ new Error("@kirana-style/webpack/loader runs only through the Kirana plugin: add `new KiranaPlugin()` to `plugins`"));
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const file = this.resourcePath;
|
|
17
|
+
session.driver().then((driver) => {
|
|
18
|
+
if (file === session.stylesheetFile) {
|
|
19
|
+
if (session.live) {
|
|
20
|
+
this.addDependency(session.live);
|
|
21
|
+
callback(null, driver.stylesheet(false));
|
|
22
|
+
} else callback(null, PLACEHOLDER);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (!shouldCompile(file + this.resourceQuery, source, driver.libraries)) {
|
|
26
|
+
callback(null, source, map);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const result = driver.transform(file, source);
|
|
30
|
+
session.compiled.add(file);
|
|
31
|
+
for (const dependency of result.dependencies) this.addDependency(dependency);
|
|
32
|
+
session.reporter.module({
|
|
33
|
+
warn: (message) => this.emitWarning(new Error(message)),
|
|
34
|
+
error: (message) => {
|
|
35
|
+
throw new Error(message);
|
|
36
|
+
}
|
|
37
|
+
}, file, source, result.diagnostics);
|
|
38
|
+
if (result.code === void 0) callback(null, source, map);
|
|
39
|
+
else callback(null, result.code, result.map && JSON.parse(result.map));
|
|
40
|
+
}).catch((error) => callback(error));
|
|
51
41
|
}
|
|
42
|
+
//#endregion
|
|
43
|
+
export { kiranaLoader as default };
|
package/src/next.d.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { KiranaWebpackOptions } from "./session.js";
|
|
2
|
+
//#region src/next.d.ts
|
|
2
3
|
type WebpackConfig = {
|
|
3
|
-
|
|
4
|
+
plugins?: unknown[];
|
|
4
5
|
};
|
|
5
6
|
type NextContext = {
|
|
6
|
-
|
|
7
|
+
dir: string;
|
|
7
8
|
};
|
|
8
9
|
type NextConfig = {
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
webpack?: (config: WebpackConfig, context: NextContext) => WebpackConfig;
|
|
11
|
+
[key: string]: unknown;
|
|
11
12
|
};
|
|
12
13
|
export declare function withKirana<Config extends NextConfig>(nextConfig?: Config, options?: KiranaWebpackOptions): Omit<Config, "webpack"> & Required<Pick<NextConfig, "webpack">>;
|
|
13
|
-
|
|
14
|
+
//#endregion
|
package/src/next.js
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Next.js with webpack (`next build --webpack`, KRN-INT-003): `withKirana` adds the plugin to every
|
|
3
|
-
* compiler Next creates — server, client and edge — at the project directory, and keeps any
|
|
4
|
-
* `webpack` function the configuration already has. For Turbopack, `@kirana-style/next` configures both.
|
|
5
|
-
*/
|
|
6
1
|
import { KiranaPlugin } from "./index.js";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
2
|
+
//#region src/next.ts
|
|
3
|
+
/**
|
|
4
|
+
* Next.js with webpack (`next build --webpack`, KRN-INT-003): `withKirana` adds the plugin to every
|
|
5
|
+
* compiler Next creates — server, client and edge — at the project directory, and keeps any
|
|
6
|
+
* `webpack` function the configuration already has. For Turbopack, `@kirana-style/next` configures both.
|
|
7
|
+
*/
|
|
8
|
+
function withKirana(nextConfig = {}, options = {}) {
|
|
9
|
+
return {
|
|
10
|
+
...nextConfig,
|
|
11
|
+
webpack(config, context) {
|
|
12
|
+
(config.plugins ??= []).push(new KiranaPlugin({
|
|
13
|
+
root: context.dir,
|
|
14
|
+
...options
|
|
15
|
+
}));
|
|
16
|
+
return nextConfig.webpack ? nextConfig.webpack(config, context) : config;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
16
19
|
}
|
|
20
|
+
//#endregion
|
|
21
|
+
export { withKirana };
|
package/src/session.d.ts
CHANGED
|
@@ -1,43 +1,38 @@
|
|
|
1
|
-
|
|
2
|
-
* What the plugin and the loader share: one Driver per compiler, found by an id the plugin puts in
|
|
3
|
-
* the loader's options. An id rather than the object, because Rspack hands loader options across its
|
|
4
|
-
* JavaScript–Rust boundary as data.
|
|
5
|
-
*/
|
|
6
|
-
import { Driver } from "@kirana-style/compiler";
|
|
7
|
-
import type { DriverOptions } from "@kirana-style/compiler";
|
|
1
|
+
import { Driver, DriverOptions } from "@kirana-style/compiler";
|
|
8
2
|
import { createReporter } from "@kirana-style/compiler/host";
|
|
9
|
-
import
|
|
3
|
+
import { KiranaConfig } from "@kirana-style/core/config";
|
|
4
|
+
//#region src/session.d.ts
|
|
10
5
|
export type KiranaWebpackOptions = {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
6
|
+
/** The project root: where `kirana.config.*` and `@kirana-style/core` are found. Default: the compiler's context. */
|
|
7
|
+
root?: string;
|
|
8
|
+
/** Options that override `kirana.config.*`. */
|
|
9
|
+
config?: KiranaConfig;
|
|
10
|
+
/** Report `info` diagnostics (such as `dynamic-bridged`) as warnings. */
|
|
11
|
+
reportInfo?: boolean;
|
|
12
|
+
/** Injected Driver options (tests). */
|
|
13
|
+
driver?: Pick<DriverOptions, "native" | "importModule">;
|
|
14
|
+
/** The loader's path, in place of this package's (tests: one instance of the loader to measure). */
|
|
15
|
+
loader?: string;
|
|
21
16
|
};
|
|
22
17
|
export type Session = {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
18
|
+
root: string;
|
|
19
|
+
/** `@kirana-style/core/stylesheet.css` as the compiler resolves it. */
|
|
20
|
+
stylesheetFile: string;
|
|
21
|
+
minify: boolean;
|
|
22
|
+
driver: () => Promise<Driver>;
|
|
23
|
+
reporter: ReturnType<typeof createReporter>;
|
|
24
|
+
/**
|
|
25
|
+
* The scripts this process's loader compiled. A persistent cache (`cache: { type: "filesystem" }`,
|
|
26
|
+
* which Meteor turns on) hands back a module without running loaders, so the plugin compiles the
|
|
27
|
+
* rest from disk before it writes the stylesheet.
|
|
28
|
+
*/
|
|
29
|
+
compiled: Set<string>;
|
|
30
|
+
/**
|
|
31
|
+
* Set while the compiler watches (a dev server, `--watch`): the stylesheet entry then holds the
|
|
32
|
+
* live stylesheet and depends on this file, which the plugin rewrites when the stylesheet changes
|
|
33
|
+
* so the bundler rebuilds the entry and sends its own CSS hot update (KRN-INT-009).
|
|
34
|
+
*/
|
|
35
|
+
live?: string;
|
|
41
36
|
};
|
|
42
37
|
/**
|
|
43
38
|
* Registries live on `globalThis` under registered symbols, because the loader is loaded by the
|
|
@@ -46,3 +41,4 @@ export type Session = {
|
|
|
46
41
|
*/
|
|
47
42
|
export declare const sessions: Map<string, Session>;
|
|
48
43
|
export declare function createSession(options: KiranaWebpackOptions, root: string, stylesheetFile: string, minify: boolean): string;
|
|
44
|
+
//#endregion
|
package/src/session.js
CHANGED
|
@@ -1,51 +1,57 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* What the plugin and the loader share: one Driver per compiler, found by an id the plugin puts in
|
|
3
|
-
* the loader's options. An id rather than the object, because Rspack hands loader options across its
|
|
4
|
-
* JavaScript–Rust boundary as data.
|
|
5
|
-
*/
|
|
6
1
|
import { Driver } from "@kirana-style/compiler";
|
|
7
2
|
import { createReporter } from "@kirana-style/compiler/host";
|
|
3
|
+
//#region src/session.ts
|
|
4
|
+
/**
|
|
5
|
+
* What the plugin and the loader share: one Driver per compiler, found by an id the plugin puts in
|
|
6
|
+
* the loader's options. An id rather than the object, because Rspack hands loader options across its
|
|
7
|
+
* JavaScript–Rust boundary as data.
|
|
8
|
+
*/
|
|
8
9
|
/**
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
* Registries live on `globalThis` under registered symbols, because the loader is loaded by the
|
|
11
|
+
* bundler's own module loader and may be a second instance of this module (a test runner's, or a
|
|
12
|
+
* duplicated install); every instance must find the same entries.
|
|
13
|
+
*/
|
|
14
|
+
const sessions = registry("sessions");
|
|
14
15
|
/**
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
* One Driver and one reporter per project — root and configuration — shared by every compiler that
|
|
17
|
+
* builds it. Next.js runs a server, an edge and a client compiler over one app: a server component is
|
|
18
|
+
* compiled only by the server compiler while the stylesheet is emitted by the client one, so a Driver
|
|
19
|
+
* per compiler would leave the client's stylesheet without the server components' atoms. Next.js builds
|
|
20
|
+
* the server first, so the client's stylesheet, filled at the end of its own build, holds them all.
|
|
21
|
+
* Sharing also reports a module's warnings once rather than once per compiler.
|
|
22
|
+
*/
|
|
22
23
|
const projects = registry("projects");
|
|
23
24
|
function registry(name) {
|
|
24
|
-
|
|
25
|
+
return globalThis[Symbol.for(`kirana.webpack.${name}`)] ??= /* @__PURE__ */ new Map();
|
|
25
26
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
27
|
+
function createSession(options, root, stylesheetFile, minify) {
|
|
28
|
+
const id = `kirana-${sessions.size}`;
|
|
29
|
+
const key = JSON.stringify([
|
|
30
|
+
root,
|
|
31
|
+
options.config ?? null,
|
|
32
|
+
options.reportInfo ?? false
|
|
33
|
+
]);
|
|
34
|
+
let project = options.driver ? void 0 : projects.get(key);
|
|
35
|
+
if (!project) {
|
|
36
|
+
let driver;
|
|
37
|
+
project = {
|
|
38
|
+
driver: () => driver ??= Driver.create({
|
|
39
|
+
root,
|
|
40
|
+
config: options.config,
|
|
41
|
+
...options.driver
|
|
42
|
+
}),
|
|
43
|
+
reporter: createReporter(options),
|
|
44
|
+
compiled: /* @__PURE__ */ new Set()
|
|
45
|
+
};
|
|
46
|
+
if (!options.driver) projects.set(key, project);
|
|
47
|
+
}
|
|
48
|
+
sessions.set(id, {
|
|
49
|
+
root,
|
|
50
|
+
stylesheetFile,
|
|
51
|
+
minify,
|
|
52
|
+
...project
|
|
53
|
+
});
|
|
54
|
+
return id;
|
|
51
55
|
}
|
|
56
|
+
//#endregion
|
|
57
|
+
export { createSession, sessions };
|