@stealthscale/vite-plugin-product 0.3.0 → 0.3.2
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 +5 -3
- package/dist/cyclonedx/bom.json +1 -1
- package/dist/index.d.mts +6 -3
- package/dist/index.mjs +351 -198
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -228,9 +228,11 @@ release.
|
|
|
228
228
|
the package. The entry of an ES module exports `*` and its default export. The entry of a CommonJS
|
|
229
229
|
module exports the names that Node's `require` returns.
|
|
230
230
|
- The client build runs a first build of the same configuration without the entries, and records the
|
|
231
|
-
chunk of each module. The
|
|
232
|
-
|
|
233
|
-
|
|
231
|
+
chunk of each module. The first build keeps every export of each module of a provided package that
|
|
232
|
+
states its side effects, because the entries make the second build keep them. It also records the
|
|
233
|
+
modules that those exports import. The second build places each recorded module in the chunk of
|
|
234
|
+
the same name, and each recorded CommonJS module in a chunk beside it, named with `-cjs`. Rolldown
|
|
235
|
+
builds the code that only the entries need into chunks that only the entries import.
|
|
234
236
|
- The build writes `.product/provided.json`. The file contains the URL of each provided entry and
|
|
235
237
|
the URLs of the chunks that the entry imports, without the chunks of the page's startup. It also
|
|
236
238
|
contains the installed version of each provided package and the page's fallback `language`. The
|
package/dist/cyclonedx/bom.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"$schema":"http://cyclonedx.org/schema/bom-1.7.schema.json","bomFormat":"CycloneDX","specVersion":"1.7","version":1,"metadata":{"lifecycles":[{"phase":"build"}],"tools":{"components":[{"type":"application","name":"rolldown","version":"1.2.12"},{"type":"application","name":"vite","version":"8.3.3"},{"type":"library","name":"core","group":"@arethetypeswrong","version":"0.18.5","bom-ref":"pkg:npm/%40arethetypeswrong/core@0.18.5","author":"Andrew Branch","description":"The API behind arethetypeswrong.github.io","hashes":[{"alg":"SHA-512","content":"f72b63cc6c318e6f54cfb23d6af7dbb79be542deae93db914444b3263aabce797a58abc8e9dc184e8faf277534d96aeafe64778aa97f3f386f1e129d2480230d"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40arethetypeswrong/core@0.18.5","externalReferences":[{"url":"https://github.com/arethetypeswrong/arethetypeswrong.github.io.git#packages/core","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=20"}]},{"type":"library","name":"sdk-core","group":"@stealthscale","version":"0.3.0","bom-ref":"pkg:npm/%40stealthscale/sdk-core@0.3.0","description":"Declares the contracts and manifests of plugins, evaluates their conditions, and resolves a product from them, without loading another package at run time.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/sdk-core@0.3.0","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#sdk/core","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/sdk/core#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"testing-config","group":"@stealthscale","version":"0.6.0","bom-ref":"pkg:npm/%40stealthscale/testing-config@0.6.0","description":"Lists every part of the house contract a config, plugin or library package breaks.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/testing-config@0.6.0","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#packages/testing-config","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/packages/testing-config#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"testing","group":"@stealthscale","version":"0.4.0","bom-ref":"pkg:npm/%40stealthscale/testing@0.4.0","description":"Supplies the scratch workspaces, manifests, element measurements and plugin drivers a specification needs.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/testing@0.4.0","externalReferences":[{"url":"git+https://github.com/stealth-scale/scale.git#packages/testing","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"vite-config-typescript","group":"@stealthscale","version":"0.3.0","bom-ref":"pkg:npm/%40stealthscale/vite-config-typescript@0.3.0","description":"Sets the TypeScript options every stealthscale package compiles with.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/vite-config-typescript@0.3.0","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#packages/vite-config-typescript","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/packages/vite-config-typescript#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"vite-config","group":"@stealthscale","version":"0.8.0","bom-ref":"pkg:npm/%40stealthscale/vite-config@0.8.0","description":"Configures a package from five Vite+ tiers and a named layer for every block.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/vite-config@0.8.0","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#packages/vite-config","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/packages/vite-config#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"vite-plugin-base","group":"@stealthscale","version":"0.4.0","bom-ref":"pkg:npm/%40stealthscale/vite-plugin-base@0.4.0","description":"Turns a name and one write step into a bundler plugin that reads the module graph.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/vite-plugin-base@0.4.0","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#packages/vite-plugin-base","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/packages/vite-plugin-base#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"vite-plugin-i18n","group":"@stealthscale","version":"0.3.1","bom-ref":"pkg:npm/%40stealthscale/vite-plugin-i18n@0.3.1","description":"Finds every catalogue an application can reach, types their keys, and answers the module it loads them from.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/vite-plugin-i18n@0.3.1","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#packages/vite-plugin-i18n","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/packages/vite-plugin-i18n#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"node","group":"@types","version":"26.6.4","bom-ref":"pkg:npm/%40types/node@26.6.4","description":"TypeScript definitions for node","hashes":[{"alg":"SHA-512","content":"95d54f0c2ce3edfb1a199acb07436e1ee4ef25cb0d6accac040a8ca25aff720c6b2ddd716eac48af75c988f9c71c9502c63e6c345d6f9d18fd6969eb561e4972"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40types/node@26.6.4","externalReferences":[{"url":"https://github.com/DefinitelyTyped/DefinitelyTyped.git#types/node","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node","type":"website","comment":"as detected from PackageJson property \"homepage\""}]},{"type":"library","name":"coverage-v8","group":"@vitest","version":"5.0.3","bom-ref":"pkg:npm/%40vitest/coverage-v8@5.0.3","author":"Anthony Fu <anthonyfu117@hotmail.com>","description":"V8 coverage provider for Vitest","hashes":[{"alg":"SHA-512","content":"fa496ccb3ec1bd3d6f094dbc6647f39acd486bbf170f4578d54dc552d45a6b74bebceaff117bcad4ee81bd50fb9754731239ba48e351d9ac9b3af0c37fdbb499"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40vitest/coverage-v8@5.0.3","externalReferences":[{"url":"https://github.com/vitest-dev/vitest/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs.url\""},{"url":"git+https://github.com/vitest-dev/vitest.git#packages/coverage-v8","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://vitest.dev/guide/coverage","type":"website","comment":"as detected from PackageJson property \"homepage\""}]},{"type":"library","name":"vite-plus-core","group":"@voidzero-dev","version":"1.1.0","bom-ref":"pkg:npm/%40voidzero-dev/vite-plus-core@1.1.0","author":"VoidZero Inc.","description":"The Unified Toolchain for the Web","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40voidzero-dev/vite-plus-core@1.1.0","externalReferences":[{"url":"https://github.com/voidzero-dev/vite-plus/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs.url\""},{"url":"git+https://github.com/voidzero-dev/vite-plus.git#packages/core","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://viteplus.dev/guide","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":"^20.19.0 || ^22.18.0 || >=24.11.0"}]},{"type":"library","name":"typescript","version":"7.0.2","bom-ref":"pkg:npm/typescript@7.0.2","author":"Microsoft Corp.","description":"TypeScript is a language for application scale JavaScript development","hashes":[{"alg":"SHA-512","content":"f0561abbdea8dcd28e85b8ca8bfa8dbc6fd6e63873c646dd9b9b23f406d9ff94f9b16aa7de12602df1b1dbbb11299593bf2cc23fc74b4414dfe6d05349155434"}],"licenses":[{"license":{"id":"Apache-2.0"}}],"purl":"pkg:npm/typescript@7.0.2","externalReferences":[{"url":"https://github.com/microsoft/TypeScript/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs.url\""},{"url":"https://github.com/microsoft/TypeScript.git","type":"vcs","comment":"as detected from PackageJson property \"repository.url\""},{"url":"https://www.typescriptlang.org/","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=16.20.0"}]},{"type":"library","name":"vitest","version":"5.0.3","bom-ref":"pkg:npm/vitest@5.0.3","author":"Anthony Fu <anthonyfu117@hotmail.com>","description":"Next generation testing framework powered by Vite","hashes":[{"alg":"SHA-512","content":"c4cc3ded2deb8ddb63e5d9156adee30aca96069bdc86cdd196941cb54ab0243d0a904464e34bf3d9f27bee50f05bf57387fa64d7c788b5803392876149eb378d"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/vitest@5.0.3","externalReferences":[{"url":"https://github.com/vitest-dev/vitest/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs.url\""},{"url":"git+https://github.com/vitest-dev/vitest.git#packages/vitest","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://vitest.dev","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":"^22.12.0 || ^24.0.0 || >=26.0.0"}]}]},"component":{"type":"library","name":"vite-plugin-product","group":"@stealthscale","version":"0.3.0","bom-ref":"pkg:npm/%40stealthscale/vite-plugin-product@0.3.0","description":"Composes a product from its plugins while it builds: checks every plugin against the others, resolves the product, and serves it as virtual:product.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/vite-plugin-product@0.3.0","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#packages/vite-plugin-product","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/packages/vite-plugin-product#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}],"evidence":{"licenses":[{"license":{"name":"file: LICENSE","text":{"content":"TUlUIExpY2Vuc2UKCkNvcHlyaWdodCAoYykgMjAyNiBTdGVhbHRoIFNjYWxlIEIuVi4KClBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHkKb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgIlNvZnR3YXJlIiksIHRvIGRlYWwKaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0cwp0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsCmNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpcwpmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOgoKVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsCmNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuCgpUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUgpJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSwKRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFCkFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIKTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSwKT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTiBUSEUKU09GVFdBUkUuCg==","contentType":"text/plain","encoding":"base64"}}}]}},"supplier":{"name":"Stealth Scale B.V.","url":["https://stealthscale.io"]}},"components":[],"dependencies":[{"ref":"pkg:npm/%40stealthscale/vite-plugin-product@0.3.0"}]}
|
|
1
|
+
{"$schema":"http://cyclonedx.org/schema/bom-1.7.schema.json","bomFormat":"CycloneDX","specVersion":"1.7","version":1,"metadata":{"lifecycles":[{"phase":"build"}],"tools":{"components":[{"type":"application","name":"rolldown","version":"1.2.12"},{"type":"application","name":"vite","version":"8.3.3"},{"type":"library","name":"core","group":"@arethetypeswrong","version":"0.18.5","bom-ref":"pkg:npm/%40arethetypeswrong/core@0.18.5","author":"Andrew Branch","description":"The API behind arethetypeswrong.github.io","hashes":[{"alg":"SHA-512","content":"f72b63cc6c318e6f54cfb23d6af7dbb79be542deae93db914444b3263aabce797a58abc8e9dc184e8faf277534d96aeafe64778aa97f3f386f1e129d2480230d"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40arethetypeswrong/core@0.18.5","externalReferences":[{"url":"https://github.com/arethetypeswrong/arethetypeswrong.github.io.git#packages/core","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=20"}]},{"type":"library","name":"sdk-core","group":"@stealthscale","version":"0.3.0","bom-ref":"pkg:npm/%40stealthscale/sdk-core@0.3.0","description":"Declares the contracts and manifests of plugins, evaluates their conditions, and resolves a product from them, without loading another package at run time.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/sdk-core@0.3.0","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#sdk/core","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/sdk/core#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"testing-config","group":"@stealthscale","version":"0.6.0","bom-ref":"pkg:npm/%40stealthscale/testing-config@0.6.0","description":"Lists every part of the house contract a config, plugin or library package breaks.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/testing-config@0.6.0","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#packages/testing-config","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/packages/testing-config#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"testing","group":"@stealthscale","version":"0.4.0","bom-ref":"pkg:npm/%40stealthscale/testing@0.4.0","description":"Supplies the scratch workspaces, manifests, element measurements and plugin drivers a specification needs.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/testing@0.4.0","externalReferences":[{"url":"git+https://github.com/stealth-scale/scale.git#packages/testing","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"vite-config-typescript","group":"@stealthscale","version":"0.3.0","bom-ref":"pkg:npm/%40stealthscale/vite-config-typescript@0.3.0","description":"Sets the TypeScript options every stealthscale package compiles with.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/vite-config-typescript@0.3.0","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#packages/vite-config-typescript","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/packages/vite-config-typescript#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"vite-config","group":"@stealthscale","version":"0.8.0","bom-ref":"pkg:npm/%40stealthscale/vite-config@0.8.0","description":"Configures a package from five Vite+ tiers and a named layer for every block.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/vite-config@0.8.0","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#packages/vite-config","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/packages/vite-config#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"vite-plugin-base","group":"@stealthscale","version":"0.5.1","bom-ref":"pkg:npm/%40stealthscale/vite-plugin-base@0.5.1","description":"Turns a name and one write step into a bundler plugin that reads the module graph.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/vite-plugin-base@0.5.1","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#packages/vite-plugin-base","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/packages/vite-plugin-base#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"vite-plugin-i18n","group":"@stealthscale","version":"0.4.0","bom-ref":"pkg:npm/%40stealthscale/vite-plugin-i18n@0.4.0","description":"Finds every catalogue an application can reach, types their keys, and answers the module it loads them from.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/vite-plugin-i18n@0.4.0","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#packages/vite-plugin-i18n","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/packages/vite-plugin-i18n#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"node","group":"@types","version":"26.6.4","bom-ref":"pkg:npm/%40types/node@26.6.4","description":"TypeScript definitions for node","hashes":[{"alg":"SHA-512","content":"95d54f0c2ce3edfb1a199acb07436e1ee4ef25cb0d6accac040a8ca25aff720c6b2ddd716eac48af75c988f9c71c9502c63e6c345d6f9d18fd6969eb561e4972"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40types/node@26.6.4","externalReferences":[{"url":"https://github.com/DefinitelyTyped/DefinitelyTyped.git#types/node","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node","type":"website","comment":"as detected from PackageJson property \"homepage\""}]},{"type":"library","name":"coverage-v8","group":"@vitest","version":"5.0.3","bom-ref":"pkg:npm/%40vitest/coverage-v8@5.0.3","author":"Anthony Fu <anthonyfu117@hotmail.com>","description":"V8 coverage provider for Vitest","hashes":[{"alg":"SHA-512","content":"fa496ccb3ec1bd3d6f094dbc6647f39acd486bbf170f4578d54dc552d45a6b74bebceaff117bcad4ee81bd50fb9754731239ba48e351d9ac9b3af0c37fdbb499"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40vitest/coverage-v8@5.0.3","externalReferences":[{"url":"https://github.com/vitest-dev/vitest/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs.url\""},{"url":"git+https://github.com/vitest-dev/vitest.git#packages/coverage-v8","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://vitest.dev/guide/coverage","type":"website","comment":"as detected from PackageJson property \"homepage\""}]},{"type":"library","name":"vite-plus-core","group":"@voidzero-dev","version":"1.1.0","bom-ref":"pkg:npm/%40voidzero-dev/vite-plus-core@1.1.0","author":"VoidZero Inc.","description":"The Unified Toolchain for the Web","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40voidzero-dev/vite-plus-core@1.1.0","externalReferences":[{"url":"https://github.com/voidzero-dev/vite-plus/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs.url\""},{"url":"git+https://github.com/voidzero-dev/vite-plus.git#packages/core","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://viteplus.dev/guide","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":"^20.19.0 || ^22.18.0 || >=24.11.0"}]},{"type":"library","name":"typescript","version":"7.0.2","bom-ref":"pkg:npm/typescript@7.0.2","author":"Microsoft Corp.","description":"TypeScript is a language for application scale JavaScript development","hashes":[{"alg":"SHA-512","content":"f0561abbdea8dcd28e85b8ca8bfa8dbc6fd6e63873c646dd9b9b23f406d9ff94f9b16aa7de12602df1b1dbbb11299593bf2cc23fc74b4414dfe6d05349155434"}],"licenses":[{"license":{"id":"Apache-2.0"}}],"purl":"pkg:npm/typescript@7.0.2","externalReferences":[{"url":"https://github.com/microsoft/TypeScript/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs.url\""},{"url":"https://github.com/microsoft/TypeScript.git","type":"vcs","comment":"as detected from PackageJson property \"repository.url\""},{"url":"https://www.typescriptlang.org/","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=16.20.0"}]},{"type":"library","name":"vitest","version":"5.0.3","bom-ref":"pkg:npm/vitest@5.0.3","author":"Anthony Fu <anthonyfu117@hotmail.com>","description":"Next generation testing framework powered by Vite","hashes":[{"alg":"SHA-512","content":"c4cc3ded2deb8ddb63e5d9156adee30aca96069bdc86cdd196941cb54ab0243d0a904464e34bf3d9f27bee50f05bf57387fa64d7c788b5803392876149eb378d"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/vitest@5.0.3","externalReferences":[{"url":"https://github.com/vitest-dev/vitest/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs.url\""},{"url":"git+https://github.com/vitest-dev/vitest.git#packages/vitest","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://vitest.dev","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":"^22.12.0 || ^24.0.0 || >=26.0.0"}]}]},"component":{"type":"library","name":"vite-plugin-product","group":"@stealthscale","version":"0.3.2","bom-ref":"pkg:npm/%40stealthscale/vite-plugin-product@0.3.2","description":"Composes a product from its plugins while it builds: checks every plugin against the others, resolves the product, and serves it as virtual:product.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/vite-plugin-product@0.3.2","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#packages/vite-plugin-product","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/packages/vite-plugin-product#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}],"evidence":{"licenses":[{"license":{"name":"file: LICENSE","text":{"content":"TUlUIExpY2Vuc2UKCkNvcHlyaWdodCAoYykgMjAyNiBTdGVhbHRoIFNjYWxlIEIuVi4KClBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHkKb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgIlNvZnR3YXJlIiksIHRvIGRlYWwKaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0cwp0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsCmNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpcwpmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOgoKVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsCmNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuCgpUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUgpJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSwKRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFCkFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIKTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSwKT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTiBUSEUKU09GVFdBUkUuCg==","contentType":"text/plain","encoding":"base64"}}}]}},"supplier":{"name":"Stealth Scale B.V.","url":["https://stealthscale.io"]}},"components":[],"dependencies":[{"ref":"pkg:npm/%40stealthscale/vite-plugin-product@0.3.2"}]}
|
package/dist/index.d.mts
CHANGED
|
@@ -107,9 +107,12 @@ export declare function product(options?: ProductOptions): Plugin;
|
|
|
107
107
|
* Creates the plugin that provides the product's shared modules to the releases its page loads.
|
|
108
108
|
*
|
|
109
109
|
* @remarks
|
|
110
|
-
* The client build first runs a build of the same configuration without the facades.
|
|
111
|
-
*
|
|
112
|
-
*
|
|
110
|
+
* The client build first runs a build of the same configuration without the facades. The first
|
|
111
|
+
* build keeps every export of each module of a provided package that it includes, as the facades
|
|
112
|
+
* make the client build keep them. A package qualifies where it states which of its files have
|
|
113
|
+
* side effects. The client build then builds each module of the first build into the chunk of the
|
|
114
|
+
* same name, and each CommonJS module into a chunk beside it. It emits each facade as an entry
|
|
115
|
+
* chunk that keeps its exports.
|
|
113
116
|
* A facade imports its specifier, and the plugin resolves the specifier from the package that
|
|
114
117
|
* depends on it, so the facade and the product share one module. Rolldown builds the code that
|
|
115
118
|
* only the facades need into chunks that only the facades import. The plugin writes
|
package/dist/index.mjs
CHANGED
|
@@ -3,33 +3,38 @@ import { build, normalizePath, parseSync } from "vite";
|
|
|
3
3
|
import { PROVIDED_FILE, RELEASE_FILE, lineOf, releaseProblems, resolveProduct } from "@stealthscale/sdk-core";
|
|
4
4
|
import { dependencies, exportTarget, importer, literal, manifestAt, owning, packageAt, quoted, text } from "@stealthscale/vite-plugin-base";
|
|
5
5
|
import { LOCALES, cataloguesOf } from "@stealthscale/vite-plugin-i18n";
|
|
6
|
-
import { dirname, isAbsolute, join, posix, relative, resolve, sep } from "node:path";
|
|
6
|
+
import { basename, dirname, extname, isAbsolute, join, matchesGlob, posix, relative, resolve, sep } from "node:path";
|
|
7
7
|
import { validateHotkey } from "@tanstack/hotkeys";
|
|
8
8
|
import { existsSync, mkdirSync, readFileSync, realpathSync, writeFileSync } from "node:fs";
|
|
9
9
|
import { createHash } from "node:crypto";
|
|
10
10
|
//#region src/page.ts
|
|
11
11
|
/**
|
|
12
|
-
* Writes the document and the entry of
|
|
13
|
-
* or a plugin's standalone page.
|
|
12
|
+
* Writes the document and the entry of the page that the plugin serves at `index.html`. The page
|
|
13
|
+
* is a product's page or a plugin's standalone page.
|
|
14
14
|
*/
|
|
15
15
|
/**
|
|
16
16
|
* The page's document, from the project root.
|
|
17
17
|
*/
|
|
18
18
|
const DOCUMENT = "index.html";
|
|
19
19
|
/**
|
|
20
|
-
* The language of a document whose page
|
|
20
|
+
* The language of a document whose page has no language.
|
|
21
21
|
*/
|
|
22
22
|
const LANGUAGE = "en-US";
|
|
23
23
|
/**
|
|
24
|
-
* Returns the path of the page's document for a specifier
|
|
24
|
+
* Returns the path of the page's document for a specifier of the document, and undefined for any
|
|
25
25
|
* other specifier.
|
|
26
26
|
*
|
|
27
|
+
* @remarks
|
|
28
|
+
* The function compares the specifier after `normalizePath`. A build's default input is the
|
|
29
|
+
* document's path from `path.resolve`, which has backslashes on Windows.
|
|
27
30
|
* @param root - The project root.
|
|
28
|
-
* @param id - The specifier
|
|
31
|
+
* @param id - The specifier. The document's specifiers are `index.html`, `/index.html` and the
|
|
32
|
+
* document's path.
|
|
29
33
|
*/
|
|
30
34
|
function documentIdOf(root, id) {
|
|
31
35
|
const document = normalizePath(join(root, DOCUMENT));
|
|
32
|
-
|
|
36
|
+
const file = normalizePath(id);
|
|
37
|
+
return file === DOCUMENT || file === `/${DOCUMENT}` || file === document ? document : void 0;
|
|
33
38
|
}
|
|
34
39
|
/**
|
|
35
40
|
* Returns the specifier of a module by its path from the project root, such as `/src/glyphs.tsx`.
|
|
@@ -38,8 +43,8 @@ function rootedOf(path) {
|
|
|
38
43
|
return posix.join("/", normalizePath(path));
|
|
39
44
|
}
|
|
40
45
|
/**
|
|
41
|
-
* Returns the source of a page's document
|
|
42
|
-
* and the entry.
|
|
46
|
+
* Returns the source of a page's document. The document has its language and title, an element
|
|
47
|
+
* with the id `root`, and the entry.
|
|
43
48
|
*/
|
|
44
49
|
function documentSource({ entry, language, title }) {
|
|
45
50
|
return [
|
|
@@ -59,18 +64,18 @@ function documentSource({ entry, language, title }) {
|
|
|
59
64
|
].join("\n");
|
|
60
65
|
}
|
|
61
66
|
/**
|
|
62
|
-
* Returns the source of a page's entry
|
|
63
|
-
* through `import()`, and
|
|
67
|
+
* Returns the source of a page's entry. The entry imports the stylesheet and the static modules,
|
|
68
|
+
* imports every other module through `import()`, and calls the render function with the members.
|
|
64
69
|
*
|
|
65
70
|
* @remarks
|
|
66
71
|
* The entry imports the stylesheet and modules without components statically, and the page's
|
|
67
72
|
* other modules through `import()`. The bundled dev server installs the React refresh runtime in
|
|
68
|
-
* the entry's own body
|
|
69
|
-
* component in a chunk the
|
|
70
|
-
* the
|
|
71
|
-
*
|
|
72
|
-
* entry
|
|
73
|
-
* bundler move every module it shares with a lazy module into a chunk of its own.
|
|
73
|
+
* the entry's own body. A chunk that the entry imports statically runs before that body, so a
|
|
74
|
+
* component in a chunk that the entry shares with a lazy module would run before the runtime and
|
|
75
|
+
* throw. A component that the entry imports through `import()` runs after the runtime. A module
|
|
76
|
+
* that only the entry imports statically builds into the entry's chunk, so it adds no chunk of
|
|
77
|
+
* its own. The entry does not await at its top level, because a module with a top-level await
|
|
78
|
+
* makes the bundler move every module it shares with a lazy module into a chunk of its own.
|
|
74
79
|
* @param render - The name of the render function, which the first module exports.
|
|
75
80
|
* @param modules - The modules the entry imports through `import()`, the render function's first.
|
|
76
81
|
* @param members - The members of the object the render function receives.
|
|
@@ -428,22 +433,22 @@ function moduleOf(definition, product) {
|
|
|
428
433
|
//#endregion
|
|
429
434
|
//#region src/chunks.ts
|
|
430
435
|
/**
|
|
431
|
-
* Names the chunk each module of a product builds into
|
|
432
|
-
* extension, command and settings section of the plugin shares, and under a build one chunk for the
|
|
433
|
-
* other modules outside the application that the startup or a plugin imports statically.
|
|
436
|
+
* Names the chunk that each module of a product builds into.
|
|
434
437
|
*
|
|
435
438
|
* @remarks
|
|
436
|
-
*
|
|
437
|
-
*
|
|
438
|
-
*
|
|
439
|
-
*
|
|
440
|
-
*
|
|
441
|
-
*
|
|
442
|
-
*
|
|
443
|
-
*
|
|
444
|
-
*
|
|
445
|
-
*
|
|
446
|
-
*
|
|
439
|
+
* Each plugin has one chunk for its pages, extensions, commands and settings sections. A build
|
|
440
|
+
* also has one chunk for the other modules outside the application that the startup or a plugin
|
|
441
|
+
* imports statically. The product's definition imports the main entry of each web package
|
|
442
|
+
* statically. The main entry and every module it imports statically build into the chunks that
|
|
443
|
+
* the entry loads, because in the plugin's chunk they would make the first load fetch the whole
|
|
444
|
+
* plugin. Groups that place a module by its path alone make rolldown 1.2 build a module that no
|
|
445
|
+
* group takes into the chunk of a lazy module that imports it. Rolldown then exports the module
|
|
446
|
+
* from that chunk to the chunks that need it, and `import()` of the lazy module resolves to a
|
|
447
|
+
* namespace with the other module's exports as well. A module outside every web package that
|
|
448
|
+
* only one plugin's lazy modules import goes into the plugin's chunk. Every other module outside
|
|
449
|
+
* the application that the startup or a plugin's modules import statically goes into the
|
|
450
|
+
* `dependencies` chunk. A lazy module's chunk then contains the lazy module alone. A module that
|
|
451
|
+
* only another `import()` loads keeps its own chunk and does not load with the startup.
|
|
447
452
|
*/
|
|
448
453
|
/**
|
|
449
454
|
* Name of the chunk that a module outside the application builds into where the startup or a
|
|
@@ -451,12 +456,13 @@ function moduleOf(definition, product) {
|
|
|
451
456
|
*/
|
|
452
457
|
const DEPENDENCIES = "dependencies";
|
|
453
458
|
/**
|
|
454
|
-
* Priority of the plugin chunks' group
|
|
459
|
+
* Priority of the plugin chunks' group. It is above the shared chunk's 3 and below the vendor
|
|
460
|
+
* chunk's 5.
|
|
455
461
|
*/
|
|
456
462
|
const PRIORITY = 4;
|
|
457
463
|
/**
|
|
458
|
-
* Priority of the dependencies' group
|
|
459
|
-
*
|
|
464
|
+
* Priority of the dependencies' group. It is below the priority of every other group, so the group
|
|
465
|
+
* claims only the modules that the other groups leave.
|
|
460
466
|
*/
|
|
461
467
|
const LAST = 1;
|
|
462
468
|
/**
|
|
@@ -466,13 +472,18 @@ const INSTALLED = /(?:^|[\\/])node_modules[\\/]/u;
|
|
|
466
472
|
/**
|
|
467
473
|
* Returns the id of the plugin whose web package contains a module, or undefined for a module
|
|
468
474
|
* outside every web package.
|
|
475
|
+
*
|
|
476
|
+
* @remarks
|
|
477
|
+
* The web packages' directories have forward slashes. The function compares the module's id
|
|
478
|
+
* after `normalizePath`, so an id with backslashes on Windows matches too.
|
|
469
479
|
*/
|
|
470
480
|
function ownerOf(id, packages) {
|
|
471
|
-
|
|
481
|
+
const file = normalizePath(id);
|
|
482
|
+
return Object.entries(packages).find(([, { directory }]) => file.startsWith(`${directory}/`))?.[0];
|
|
472
483
|
}
|
|
473
484
|
/**
|
|
474
|
-
* Returns true where the walk over a module's static importers meets a module the test
|
|
475
|
-
* the module itself
|
|
485
|
+
* Returns true where the walk over a module's static importers meets a module that the test
|
|
486
|
+
* accepts. The walk starts at the module itself.
|
|
476
487
|
*/
|
|
477
488
|
function leadsTo(id, chunking, ends) {
|
|
478
489
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -492,28 +503,28 @@ function startup(id, info) {
|
|
|
492
503
|
return id === RESOLVED || info?.isEntry === true;
|
|
493
504
|
}
|
|
494
505
|
/**
|
|
495
|
-
* Returns true where an entry of the build or `virtual:product` imports a module statically
|
|
496
|
-
*
|
|
506
|
+
* Returns true where an entry of the build or `virtual:product` imports a module statically. The
|
|
507
|
+
* import may pass through other modules.
|
|
497
508
|
*
|
|
498
509
|
* @remarks
|
|
499
|
-
* The walk follows each module's static importers back towards the entries
|
|
500
|
-
* `virtual:product`, because every module the product imports statically loads with it. The
|
|
501
|
-
* standalone page's entry imports the product through `import()`,
|
|
502
|
-
* definition statically there. A dynamic import ends the walk elsewhere, because
|
|
503
|
-
*
|
|
510
|
+
* The walk follows each module's static importers back towards the entries. It ends at
|
|
511
|
+
* `virtual:product`, because every module that the product imports statically loads with it. The
|
|
512
|
+
* standalone page's entry imports the product through `import()`, and no entry imports the
|
|
513
|
+
* definition statically there. A dynamic import ends the walk elsewhere, because the module that
|
|
514
|
+
* it imports loads after the entry.
|
|
504
515
|
*/
|
|
505
516
|
function initial(id, chunking) {
|
|
506
517
|
return leadsTo(id, chunking, startup);
|
|
507
518
|
}
|
|
508
519
|
/**
|
|
509
|
-
* Returns the one plugin whose web package's modules import a module outside every web package
|
|
510
|
-
*
|
|
520
|
+
* Returns the one plugin whose web package's modules import a module outside every web package.
|
|
521
|
+
* The import may pass through other modules.
|
|
511
522
|
*
|
|
512
523
|
* @remarks
|
|
513
|
-
*
|
|
514
|
-
* walk meets a module outside every web package that no module imports
|
|
515
|
-
* page of the application
|
|
516
|
-
* plugins import
|
|
524
|
+
* The function returns undefined in four cases. An entry or `virtual:product` imports the module
|
|
525
|
+
* statically. The walk meets a module outside every web package that no module imports
|
|
526
|
+
* statically, such as a lazy page of the application. The walk meets a module that the build does
|
|
527
|
+
* not know. The modules of two plugins import the module.
|
|
517
528
|
*/
|
|
518
529
|
function soleOwnerOf(id, chunking, packages) {
|
|
519
530
|
const owners = /* @__PURE__ */ new Set();
|
|
@@ -534,11 +545,13 @@ function soleOwnerOf(id, chunking, packages) {
|
|
|
534
545
|
return owners.size === 1 ? sole : void 0;
|
|
535
546
|
}
|
|
536
547
|
/**
|
|
537
|
-
* Returns the chunk a module builds into
|
|
538
|
-
* package that no entry imports statically, and for a module outside every web package that only
|
|
539
|
-
* that plugin's lazy modules import, and null for every other module.
|
|
548
|
+
* Returns the plugin chunk that a module builds into, or null for a module of no plugin chunk.
|
|
540
549
|
*
|
|
541
|
-
* @
|
|
550
|
+
* @remarks
|
|
551
|
+
* A module of an installed plugin's web package that no entry imports statically builds into
|
|
552
|
+
* `plugin-<id>`. A module outside every web package that only that plugin's lazy modules import
|
|
553
|
+
* builds into the same chunk.
|
|
554
|
+
* @param id - The module's id. A file's id is its absolute path.
|
|
542
555
|
* @param chunking - The context rolldown passes a group's name function.
|
|
543
556
|
* @param packages - Each installed plugin's web package, by plugin id.
|
|
544
557
|
*/
|
|
@@ -549,17 +562,17 @@ function pluginChunkOf(id, chunking, packages) {
|
|
|
549
562
|
return sole === void 0 ? null : `plugin-${sole}`;
|
|
550
563
|
}
|
|
551
564
|
/**
|
|
552
|
-
* Returns
|
|
553
|
-
*
|
|
554
|
-
* statically, and null for every other module.
|
|
565
|
+
* Returns `dependencies` for a module outside the application that the startup or a plugin's
|
|
566
|
+
* modules import statically, and null for every other module.
|
|
555
567
|
*
|
|
556
568
|
* @remarks
|
|
557
|
-
*
|
|
558
|
-
*
|
|
559
|
-
* at an entry, at `virtual:product` and at
|
|
560
|
-
* module
|
|
561
|
-
*
|
|
562
|
-
*
|
|
569
|
+
* The groups with a higher priority place a module first. A module of the application is a file
|
|
570
|
+
* under the project root and outside its `node_modules`. A virtual module's id is not an absolute
|
|
571
|
+
* path. The walk over the module's static importers ends at an entry, at `virtual:product` and at
|
|
572
|
+
* a module of an installed plugin's web package. A page that the application loads on demand is a
|
|
573
|
+
* module that only another `import()` loads. The walk does not meet such a module, and the module
|
|
574
|
+
* keeps its own chunk.
|
|
575
|
+
* @param id - The module's id. A file's id is its absolute path.
|
|
563
576
|
* @param chunking - The context rolldown passes a group's name function.
|
|
564
577
|
* @param root - The project root.
|
|
565
578
|
* @param packages - Each installed plugin's web package, by plugin id.
|
|
@@ -572,16 +585,17 @@ function dependencyChunkOf(id, chunking, root, packages) {
|
|
|
572
585
|
}
|
|
573
586
|
/**
|
|
574
587
|
* Returns the configuration whose groups build each installed plugin's lazy modules into a chunk
|
|
575
|
-
* of its own
|
|
576
|
-
* plugin imports statically into the `dependencies` chunk.
|
|
588
|
+
* of its own.
|
|
577
589
|
*
|
|
578
590
|
* @remarks
|
|
579
|
-
*
|
|
580
|
-
*
|
|
581
|
-
*
|
|
582
|
-
*
|
|
583
|
-
*
|
|
584
|
-
*
|
|
591
|
+
* A build also builds every other module outside the application that the startup or a plugin
|
|
592
|
+
* imports statically into the `dependencies` chunk. Both groups read the web packages that the
|
|
593
|
+
* composition found, and the dependencies' group also reads the project root. The bundler calls
|
|
594
|
+
* both groups after the composition, when it places a module. A dev server has no dependencies'
|
|
595
|
+
* group, because `import()` of a lazy module resolves to the module's own exports there without
|
|
596
|
+
* it. `vite-config` leaves out its library and shared groups on a dev server too. Their chunks
|
|
597
|
+
* would run components before the React refresh runtime is installed.
|
|
598
|
+
* @param placing - The web packages and the project root. Each group reads them when the bundler
|
|
585
599
|
* places a module.
|
|
586
600
|
* @param command - The command Vite runs under, `build` or `serve`.
|
|
587
601
|
*/
|
|
@@ -599,15 +613,16 @@ function chunked(placing, command) {
|
|
|
599
613
|
//#endregion
|
|
600
614
|
//#region src/discover.ts
|
|
601
615
|
/**
|
|
602
|
-
* Finds each installed plugin's web package and contract package among the modules the
|
|
603
|
-
* definition loaded.
|
|
616
|
+
* Finds each installed plugin's web package and contract package among the modules that the
|
|
617
|
+
* evaluation of the product's definition loaded.
|
|
604
618
|
*
|
|
605
619
|
* @remarks
|
|
606
|
-
* The definition imports every installed plugin
|
|
607
|
-
*
|
|
608
|
-
* the
|
|
609
|
-
*
|
|
610
|
-
* the
|
|
620
|
+
* The definition module imports the manifest of every installed plugin, and each manifest
|
|
621
|
+
* contains its contract. The modules of the evaluation therefore contain both. An object belongs
|
|
622
|
+
* to the package of the module that defines it, and the search matches objects by identity. No
|
|
623
|
+
* module exports a manifest that the definition module creates itself, so that manifest belongs
|
|
624
|
+
* to the package of the definition module. The search imports no package of its own, so Node does
|
|
625
|
+
* not load a component package or React.
|
|
611
626
|
*/
|
|
612
627
|
/**
|
|
613
628
|
* Returns true where a value is an object whose members can be read by name.
|
|
@@ -616,10 +631,11 @@ function isRecord(value) {
|
|
|
616
631
|
return typeof value === "object" && value !== null;
|
|
617
632
|
}
|
|
618
633
|
/**
|
|
619
|
-
* Returns each installed plugin the definition
|
|
634
|
+
* Returns each installed plugin of the definition that has a readable manifest and contract.
|
|
620
635
|
*
|
|
621
636
|
* @remarks
|
|
622
|
-
*
|
|
637
|
+
* The function returns no plugin for a definition of another shape. The resolver's shape check
|
|
638
|
+
* reports that definition.
|
|
623
639
|
* @param definition - The definition's default export.
|
|
624
640
|
*/
|
|
625
641
|
function installationsOf(definition) {
|
|
@@ -640,9 +656,9 @@ function installationsOf(definition) {
|
|
|
640
656
|
*
|
|
641
657
|
* @remarks
|
|
642
658
|
* A module evaluates after every module it imports, and a module that re-exports an object
|
|
643
|
-
* imports the module that defines it. The first module that exports an object
|
|
644
|
-
*
|
|
645
|
-
* @param loaded - Every module the definition
|
|
659
|
+
* imports the module that defines it. The first module in evaluation order that exports an object
|
|
660
|
+
* is therefore the module that defines it.
|
|
661
|
+
* @param loaded - Every module that the evaluation of the definition loaded, in evaluation order.
|
|
646
662
|
*/
|
|
647
663
|
function ownersOf(loaded) {
|
|
648
664
|
const owners = /* @__PURE__ */ new Map();
|
|
@@ -653,13 +669,17 @@ function ownersOf(loaded) {
|
|
|
653
669
|
return owners;
|
|
654
670
|
}
|
|
655
671
|
/**
|
|
656
|
-
* Returns the package at a directory, or undefined where its manifest
|
|
672
|
+
* Returns the package at a directory, or undefined where its manifest has no name.
|
|
673
|
+
*
|
|
674
|
+
* @remarks
|
|
675
|
+
* The package's directory goes through `normalizePath`, so on Windows it has the forward slashes
|
|
676
|
+
* of a module id.
|
|
657
677
|
*/
|
|
658
678
|
function packageIn(directory) {
|
|
659
679
|
const manifest = directory === void 0 ? void 0 : manifestAt(directory);
|
|
660
680
|
const name = manifest === void 0 ? void 0 : text(manifest, "name");
|
|
661
681
|
return directory === void 0 || name === void 0 ? void 0 : {
|
|
662
|
-
directory,
|
|
682
|
+
directory: normalizePath(directory),
|
|
663
683
|
name
|
|
664
684
|
};
|
|
665
685
|
}
|
|
@@ -667,18 +687,21 @@ function packageIn(directory) {
|
|
|
667
687
|
* Finds each installed plugin's web package and contract package.
|
|
668
688
|
*
|
|
669
689
|
* @remarks
|
|
670
|
-
*
|
|
671
|
-
* resolver reports the plugin.
|
|
672
|
-
* reads it to leave the plugin's own catalogue out of the namespaces
|
|
690
|
+
* The function leaves out a web package outside the product's own package and its dependencies,
|
|
691
|
+
* so the resolver reports the plugin. It records a contract package wherever it is, because the
|
|
692
|
+
* build reads it to leave the plugin's own catalogue out of the namespaces of other packages. The
|
|
693
|
+
* function compares directories after `normalizePath`, because on Windows the module runner and
|
|
694
|
+
* `realpathSync` write them with different separators.
|
|
673
695
|
* @param definition - The definition's default export.
|
|
674
|
-
* @param loaded - Every module the definition
|
|
675
|
-
* @param root - The product's directory
|
|
676
|
-
* @param file - The definition module
|
|
696
|
+
* @param loaded - Every module that the evaluation of the definition loaded, in evaluation order.
|
|
697
|
+
* @param root - The product's directory. The walk over its dependencies starts there.
|
|
698
|
+
* @param file - The definition module. A manifest that the definition module creates belongs to the
|
|
699
|
+
* package of this module.
|
|
677
700
|
*/
|
|
678
701
|
function discover(definition, loaded, root, file) {
|
|
679
702
|
const owners = ownersOf(loaded);
|
|
680
703
|
const own = owning(realpathSync(file));
|
|
681
|
-
const depended =
|
|
704
|
+
const depended = new Set([realpathSync(root), ...dependencies(root).map(({ at }) => at)].map((at) => normalizePath(at)));
|
|
682
705
|
const contracts = {};
|
|
683
706
|
const packages = {};
|
|
684
707
|
for (const { contract, manifest, pluginId } of installationsOf(definition)) {
|
|
@@ -1417,108 +1440,6 @@ function facadeOf(specifier, shape) {
|
|
|
1417
1440
|
].join("\n");
|
|
1418
1441
|
}
|
|
1419
1442
|
//#endregion
|
|
1420
|
-
//#region src/provided/pinned.ts
|
|
1421
|
-
/**
|
|
1422
|
-
* Returns a map from the id of each module of the first build to the name of its chunk.
|
|
1423
|
-
*
|
|
1424
|
-
* @remarks
|
|
1425
|
-
* The modules of a static entry's chunk have no pin. The second chunk of one name in file name
|
|
1426
|
-
* order takes the name with `-2` appended, and the third takes it with `-3` appended.
|
|
1427
|
-
* @param chunks - The chunks of the first build.
|
|
1428
|
-
*/
|
|
1429
|
-
function pinnedOf(chunks) {
|
|
1430
|
-
const counts = /* @__PURE__ */ new Map();
|
|
1431
|
-
const pinned = /* @__PURE__ */ new Map();
|
|
1432
|
-
const ordered = chunks.filter(({ isEntry }) => !isEntry).toSorted((one, two) => one.fileName.localeCompare(two.fileName));
|
|
1433
|
-
for (const { modules, name } of ordered) {
|
|
1434
|
-
const count = (counts.get(name) ?? 0) + 1;
|
|
1435
|
-
const pin = count === 1 ? name : `${name}-${String(count)}`;
|
|
1436
|
-
counts.set(name, count);
|
|
1437
|
-
for (const id of Object.keys(modules)) pinned.set(id, pin);
|
|
1438
|
-
}
|
|
1439
|
-
return pinned;
|
|
1440
|
-
}
|
|
1441
|
-
/**
|
|
1442
|
-
* Returns the code-splitting group that places each pinned module in the second build.
|
|
1443
|
-
*
|
|
1444
|
-
* @remarks
|
|
1445
|
-
* A pinned chunk can import a chunk of the facades' code that imports it back. Rolldown defines a
|
|
1446
|
-
* CommonJS module's wrapper at the top level of its chunk, and an ES module that imports it calls
|
|
1447
|
-
* the wrapper at its own top level. In such a cycle a chunk can call a wrapper that is not
|
|
1448
|
-
* defined yet. The group builds each pin's CommonJS modules into a chunk of their own. As long as
|
|
1449
|
-
* those modules require only CommonJS modules, that chunk imports only rolldown's runtime and
|
|
1450
|
-
* other such chunks. It then runs before every chunk that calls its wrappers.
|
|
1451
|
-
* @param pins - Returns a map from the id of each module of the first build to its chunk once the
|
|
1452
|
-
* first build has run.
|
|
1453
|
-
*/
|
|
1454
|
-
function pinnedGroup(pins) {
|
|
1455
|
-
return {
|
|
1456
|
-
debugName: "pinned",
|
|
1457
|
-
name: (id, chunking) => {
|
|
1458
|
-
const pin = pins()?.get(id);
|
|
1459
|
-
if (pin === void 0) return null;
|
|
1460
|
-
return chunking.getModuleInfo(id)?.inputFormat === "cjs" ? `${pin}-cjs` : pin;
|
|
1461
|
-
}
|
|
1462
|
-
};
|
|
1463
|
-
}
|
|
1464
|
-
//#endregion
|
|
1465
|
-
//#region src/provided/first.ts
|
|
1466
|
-
/**
|
|
1467
|
-
* Runs a product's first build: the build's own configuration without the facades, written
|
|
1468
|
-
* nowhere, whose chunks the second build pins the product's modules to.
|
|
1469
|
-
*/
|
|
1470
|
-
/**
|
|
1471
|
-
* Name of the plugin that marks the first build, which leaves the facades out.
|
|
1472
|
-
*/
|
|
1473
|
-
const FIRST_BUILD = "stealth:provided-first";
|
|
1474
|
-
/**
|
|
1475
|
-
* Returns true where a configuration's plugins mark the first build.
|
|
1476
|
-
*
|
|
1477
|
-
* @param plugins - The resolved plugins of a build.
|
|
1478
|
-
*/
|
|
1479
|
-
function isFirstBuild(plugins) {
|
|
1480
|
-
return plugins.some(({ name }) => name === FIRST_BUILD);
|
|
1481
|
-
}
|
|
1482
|
-
/**
|
|
1483
|
-
* Returns a plugin option with every nested list flattened into one list.
|
|
1484
|
-
*/
|
|
1485
|
-
function flattened(option) {
|
|
1486
|
-
return Array.isArray(option) ? option.flatMap((one) => flattened(one)) : [option];
|
|
1487
|
-
}
|
|
1488
|
-
/**
|
|
1489
|
-
* Returns the plugins a caller passed inline, with the second build's own facade plugin left out.
|
|
1490
|
-
*/
|
|
1491
|
-
function inlinePlugins(plugins, own) {
|
|
1492
|
-
return (plugins ?? []).flatMap((option) => flattened(option)).filter((one) => one !== own);
|
|
1493
|
-
}
|
|
1494
|
-
/**
|
|
1495
|
-
* Returns the chunks of the first build of the configuration a second build resolved.
|
|
1496
|
-
*
|
|
1497
|
-
* @remarks
|
|
1498
|
-
* The first build reads the same configuration file and the same inline configuration, with the
|
|
1499
|
-
* plugin that marks it, without watching and without writing. A facade plugin of the first build
|
|
1500
|
-
* reads the mark and adds nothing, so the first build places each module as the product's build
|
|
1501
|
-
* does without facades.
|
|
1502
|
-
* @param config - The second build's configuration file, inline configuration, mode and root.
|
|
1503
|
-
* @param own - The second build's facade plugin, which a caller may have passed inline.
|
|
1504
|
-
*/
|
|
1505
|
-
async function firstBuild(config, own) {
|
|
1506
|
-
const { configFile, inlineConfig, mode, root } = config;
|
|
1507
|
-
return [await build({
|
|
1508
|
-
...inlineConfig,
|
|
1509
|
-
build: {
|
|
1510
|
-
...inlineConfig.build,
|
|
1511
|
-
watch: null,
|
|
1512
|
-
write: false
|
|
1513
|
-
},
|
|
1514
|
-
configFile: configFile ?? false,
|
|
1515
|
-
logLevel: "silent",
|
|
1516
|
-
mode,
|
|
1517
|
-
plugins: [...inlinePlugins(inlineConfig.plugins, own), { name: FIRST_BUILD }],
|
|
1518
|
-
root
|
|
1519
|
-
})].flat().flatMap(({ output }) => output).filter((file) => file.type === "chunk");
|
|
1520
|
-
}
|
|
1521
|
-
//#endregion
|
|
1522
1443
|
//#region src/provided/packages.ts
|
|
1523
1444
|
/**
|
|
1524
1445
|
* Lists the packages a page provides to the releases it loads, and the specifiers of each.
|
|
@@ -1666,6 +1587,235 @@ function importerOf(provided, specifier) {
|
|
|
1666
1587
|
return owner === void 0 ? void 0 : join(owner.from, "package.json");
|
|
1667
1588
|
}
|
|
1668
1589
|
//#endregion
|
|
1590
|
+
//#region src/provided/kept.ts
|
|
1591
|
+
/**
|
|
1592
|
+
* Makes a product's first build keep every export of each module of a provided package that the
|
|
1593
|
+
* build includes.
|
|
1594
|
+
*
|
|
1595
|
+
* @remarks
|
|
1596
|
+
* A facade keeps every export of its specifier's module, so the second build keeps code that the
|
|
1597
|
+
* first build removed from a module the product uses. A published package bundles its components
|
|
1598
|
+
* into few modules, and the code that the first build removed imports modules that the first
|
|
1599
|
+
* build left out. Those modules have no pin, so rolldown builds them into a chunk of their own.
|
|
1600
|
+
* That chunk imports the pinned chunk that imports it. In such a cycle a module can read a
|
|
1601
|
+
* binding of the other chunk before that chunk has run. The first build therefore appends to each
|
|
1602
|
+
* module of a provided package a statement that passes the module's namespace to a global hook.
|
|
1603
|
+
* The statement keeps every export of a module that the build includes, so the first build places
|
|
1604
|
+
* the modules that those exports import. The statement adds no module to the build. The build
|
|
1605
|
+
* leaves out a module whose exports nothing uses when its package has a `sideEffects` field.
|
|
1606
|
+
*/
|
|
1607
|
+
/**
|
|
1608
|
+
* The extensions of an ES module in any package.
|
|
1609
|
+
*/
|
|
1610
|
+
const MODULES = /* @__PURE__ */ new Set([".mjs", ".mts"]);
|
|
1611
|
+
/**
|
|
1612
|
+
* The extensions of an ES module in a package that states `"type": "module"`.
|
|
1613
|
+
*/
|
|
1614
|
+
const TYPED = /* @__PURE__ */ new Set([
|
|
1615
|
+
".js",
|
|
1616
|
+
".jsx",
|
|
1617
|
+
".ts",
|
|
1618
|
+
".tsx"
|
|
1619
|
+
]);
|
|
1620
|
+
/**
|
|
1621
|
+
* The key of the global function that the kept statement passes a module's namespace to. No page
|
|
1622
|
+
* defines the function, because no page loads the first build's output.
|
|
1623
|
+
*/
|
|
1624
|
+
const HOOK = "stealth.kept";
|
|
1625
|
+
/**
|
|
1626
|
+
* Returns the patterns of a package's files that have side effects, or undefined where the
|
|
1627
|
+
* manifest's `sideEffects` is neither false nor an array.
|
|
1628
|
+
*/
|
|
1629
|
+
function effectsOf(sideEffects) {
|
|
1630
|
+
if (sideEffects === false) return [];
|
|
1631
|
+
if (!Array.isArray(sideEffects)) return void 0;
|
|
1632
|
+
return sideEffects.filter((pattern) => typeof pattern === "string");
|
|
1633
|
+
}
|
|
1634
|
+
/**
|
|
1635
|
+
* Returns the provided packages whose modules the first build keeps whole.
|
|
1636
|
+
*
|
|
1637
|
+
* @remarks
|
|
1638
|
+
* Each is an installed package whose `sideEffects` is false or a list of patterns. Its directory
|
|
1639
|
+
* goes through `normalizePath`, so on Windows it has the forward slashes of a module id.
|
|
1640
|
+
* @param packages - The packages the product provides.
|
|
1641
|
+
*/
|
|
1642
|
+
function keptPackages(packages) {
|
|
1643
|
+
return packages.flatMap(({ from, name }) => {
|
|
1644
|
+
const directory = packageAt(name, from);
|
|
1645
|
+
const manifest = directory === void 0 ? void 0 : manifestAt(directory);
|
|
1646
|
+
const effects = effectsOf(manifest?.["sideEffects"]);
|
|
1647
|
+
return directory === void 0 || effects === void 0 ? [] : [{
|
|
1648
|
+
directory: normalizePath(directory),
|
|
1649
|
+
effects,
|
|
1650
|
+
typed: manifest?.["type"] === "module"
|
|
1651
|
+
}];
|
|
1652
|
+
});
|
|
1653
|
+
}
|
|
1654
|
+
/**
|
|
1655
|
+
* Returns true where a pattern of a package's `sideEffects` list matches a file at a path relative
|
|
1656
|
+
* to the package.
|
|
1657
|
+
*
|
|
1658
|
+
* @remarks
|
|
1659
|
+
* A pattern without a slash matches the file's name in any directory, as bundlers read the list.
|
|
1660
|
+
*/
|
|
1661
|
+
function affects(pattern, path) {
|
|
1662
|
+
return matchesGlob(path, pattern.includes("/") ? pattern.replace(/^\.\//u, "") : `**/${pattern}`);
|
|
1663
|
+
}
|
|
1664
|
+
/**
|
|
1665
|
+
* Returns true for an ES module file of a kept package that no side-effect pattern of the package
|
|
1666
|
+
* matches. The first build keeps the exports of such a module whole.
|
|
1667
|
+
*
|
|
1668
|
+
* @remarks
|
|
1669
|
+
* A file below a `node_modules` directory inside the package belongs to another package. The
|
|
1670
|
+
* function compares the id after `normalizePath`, so an id with backslashes on Windows matches
|
|
1671
|
+
* too.
|
|
1672
|
+
* @param id - The module's id.
|
|
1673
|
+
* @param packages - The packages whose modules the first build keeps whole.
|
|
1674
|
+
*/
|
|
1675
|
+
function isKept(id, packages) {
|
|
1676
|
+
const file = normalizePath(id);
|
|
1677
|
+
const owner = isAbsolute(file) ? packages.find(({ directory }) => file.startsWith(`${directory}/`)) : void 0;
|
|
1678
|
+
if (owner === void 0) return false;
|
|
1679
|
+
const path = file.slice(owner.directory.length + 1);
|
|
1680
|
+
const extension = extname(file);
|
|
1681
|
+
return (MODULES.has(extension) || owner.typed && TYPED.has(extension)) && !path.split("/").includes("node_modules") && !owner.effects.some((pattern) => affects(pattern, path));
|
|
1682
|
+
}
|
|
1683
|
+
/**
|
|
1684
|
+
* Returns a module's code with the statement that keeps its exports appended. The statement
|
|
1685
|
+
* imports the namespace of the module's own file and passes it to a global hook.
|
|
1686
|
+
*
|
|
1687
|
+
* @param code - The module's code.
|
|
1688
|
+
* @param id - The module's id, the absolute path of its file.
|
|
1689
|
+
*/
|
|
1690
|
+
function keptSourceOf(code, id) {
|
|
1691
|
+
return [
|
|
1692
|
+
code,
|
|
1693
|
+
`import * as __stealthKept from ${quoted(`./${basename(id)}`)};`,
|
|
1694
|
+
`globalThis[Symbol.for(${quoted(HOOK)})]?.(__stealthKept);`,
|
|
1695
|
+
""
|
|
1696
|
+
].join("\n");
|
|
1697
|
+
}
|
|
1698
|
+
//#endregion
|
|
1699
|
+
//#region src/provided/pinned.ts
|
|
1700
|
+
/**
|
|
1701
|
+
* Returns a map from the id of each module of the first build to the name of its chunk.
|
|
1702
|
+
*
|
|
1703
|
+
* @remarks
|
|
1704
|
+
* The modules of a static entry's chunk have no pin. The second chunk of one name in file name
|
|
1705
|
+
* order takes the name with `-2` appended, and the third takes it with `-3` appended.
|
|
1706
|
+
* @param chunks - The chunks of the first build.
|
|
1707
|
+
*/
|
|
1708
|
+
function pinnedOf(chunks) {
|
|
1709
|
+
const counts = /* @__PURE__ */ new Map();
|
|
1710
|
+
const pinned = /* @__PURE__ */ new Map();
|
|
1711
|
+
const ordered = chunks.filter(({ isEntry }) => !isEntry).toSorted((one, two) => one.fileName.localeCompare(two.fileName));
|
|
1712
|
+
for (const { modules, name } of ordered) {
|
|
1713
|
+
const count = (counts.get(name) ?? 0) + 1;
|
|
1714
|
+
const pin = count === 1 ? name : `${name}-${String(count)}`;
|
|
1715
|
+
counts.set(name, count);
|
|
1716
|
+
for (const id of Object.keys(modules)) pinned.set(id, pin);
|
|
1717
|
+
}
|
|
1718
|
+
return pinned;
|
|
1719
|
+
}
|
|
1720
|
+
/**
|
|
1721
|
+
* Returns the code-splitting group that places each pinned module in the second build.
|
|
1722
|
+
*
|
|
1723
|
+
* @remarks
|
|
1724
|
+
* A pinned chunk can import a chunk of the facades' code that imports it back. Rolldown defines a
|
|
1725
|
+
* CommonJS module's wrapper at the top level of its chunk, and an ES module that imports it calls
|
|
1726
|
+
* the wrapper at its own top level. In such a cycle a chunk can call a wrapper that is not
|
|
1727
|
+
* defined yet. The group builds each pin's CommonJS modules into a chunk of their own. As long as
|
|
1728
|
+
* those modules require only CommonJS modules, that chunk imports only rolldown's runtime and
|
|
1729
|
+
* other such chunks. It then runs before every chunk that calls its wrappers.
|
|
1730
|
+
* @param pins - Returns a map from the id of each module of the first build to its chunk once the
|
|
1731
|
+
* first build has run.
|
|
1732
|
+
*/
|
|
1733
|
+
function pinnedGroup(pins) {
|
|
1734
|
+
return {
|
|
1735
|
+
debugName: "pinned",
|
|
1736
|
+
name: (id, chunking) => {
|
|
1737
|
+
const pin = pins()?.get(id);
|
|
1738
|
+
if (pin === void 0) return null;
|
|
1739
|
+
return chunking.getModuleInfo(id)?.inputFormat === "cjs" ? `${pin}-cjs` : pin;
|
|
1740
|
+
}
|
|
1741
|
+
};
|
|
1742
|
+
}
|
|
1743
|
+
//#endregion
|
|
1744
|
+
//#region src/provided/first.ts
|
|
1745
|
+
/**
|
|
1746
|
+
* Runs a product's first build: the build's own configuration without the facades, written
|
|
1747
|
+
* nowhere, whose chunks the second build pins the product's modules to.
|
|
1748
|
+
*/
|
|
1749
|
+
/**
|
|
1750
|
+
* Name of the plugin that marks the first build, which leaves the facades out.
|
|
1751
|
+
*/
|
|
1752
|
+
const FIRST_BUILD = "stealth:provided-first";
|
|
1753
|
+
/**
|
|
1754
|
+
* Returns true where a configuration's plugins mark the first build.
|
|
1755
|
+
*
|
|
1756
|
+
* @param plugins - The resolved plugins of a build.
|
|
1757
|
+
*/
|
|
1758
|
+
function isFirstBuild(plugins) {
|
|
1759
|
+
return plugins.some(({ name }) => name === FIRST_BUILD);
|
|
1760
|
+
}
|
|
1761
|
+
/**
|
|
1762
|
+
* Returns a plugin option with every nested list flattened into one list.
|
|
1763
|
+
*/
|
|
1764
|
+
function flattened(option) {
|
|
1765
|
+
return Array.isArray(option) ? option.flatMap((one) => flattened(one)) : [option];
|
|
1766
|
+
}
|
|
1767
|
+
/**
|
|
1768
|
+
* Returns the plugins a caller passed inline, with the second build's own facade plugin left out.
|
|
1769
|
+
*/
|
|
1770
|
+
function inlinePlugins(plugins, own) {
|
|
1771
|
+
return (plugins ?? []).flatMap((option) => flattened(option)).filter((one) => one !== own);
|
|
1772
|
+
}
|
|
1773
|
+
/**
|
|
1774
|
+
* Returns the plugin that marks the first build and keeps every export of each module of a kept
|
|
1775
|
+
* package.
|
|
1776
|
+
*/
|
|
1777
|
+
function markOf(kept) {
|
|
1778
|
+
return {
|
|
1779
|
+
name: FIRST_BUILD,
|
|
1780
|
+
/**
|
|
1781
|
+
* Appends the statement that keeps every export to each module of a kept package, and leaves
|
|
1782
|
+
* every other module alone.
|
|
1783
|
+
*/
|
|
1784
|
+
transform(code, id) {
|
|
1785
|
+
return isKept(id, kept) ? keptSourceOf(code, id) : null;
|
|
1786
|
+
}
|
|
1787
|
+
};
|
|
1788
|
+
}
|
|
1789
|
+
/**
|
|
1790
|
+
* Returns the chunks of the first build of the configuration a second build resolved.
|
|
1791
|
+
*
|
|
1792
|
+
* @remarks
|
|
1793
|
+
* The first build reads the same configuration file and the same inline configuration, with the
|
|
1794
|
+
* plugin that marks it, without watching and without writing. A facade plugin of the first build
|
|
1795
|
+
* reads the mark and adds nothing. The plugin that marks the build keeps every export of each
|
|
1796
|
+
* module of a kept package that the build includes, as the facades make the second build keep
|
|
1797
|
+
* them. The first build therefore also places the modules that those exports import.
|
|
1798
|
+
* @param config - The second build's configuration file, inline configuration, mode and root.
|
|
1799
|
+
* @param own - The second build's facade plugin, which a caller may have passed inline.
|
|
1800
|
+
* @param kept - The provided packages whose modules the first build keeps whole.
|
|
1801
|
+
*/
|
|
1802
|
+
async function firstBuild(config, own, kept) {
|
|
1803
|
+
const { configFile, inlineConfig, mode, root } = config;
|
|
1804
|
+
return [await build({
|
|
1805
|
+
...inlineConfig,
|
|
1806
|
+
build: {
|
|
1807
|
+
...inlineConfig.build,
|
|
1808
|
+
watch: null,
|
|
1809
|
+
write: false
|
|
1810
|
+
},
|
|
1811
|
+
configFile: configFile ?? false,
|
|
1812
|
+
logLevel: "silent",
|
|
1813
|
+
mode,
|
|
1814
|
+
plugins: [...inlinePlugins(inlineConfig.plugins, own), markOf(kept)],
|
|
1815
|
+
root
|
|
1816
|
+
})].flat().flatMap(({ output }) => output).filter((file) => file.type === "chunk");
|
|
1817
|
+
}
|
|
1818
|
+
//#endregion
|
|
1669
1819
|
//#region src/provided/manifest.ts
|
|
1670
1820
|
/**
|
|
1671
1821
|
* Returns the paths of some chunks and of every chunk that they import statically. The given
|
|
@@ -1803,9 +1953,12 @@ async function facadeSourceOf(context, packages, id) {
|
|
|
1803
1953
|
* Creates the plugin that provides the product's shared modules to the releases its page loads.
|
|
1804
1954
|
*
|
|
1805
1955
|
* @remarks
|
|
1806
|
-
* The client build first runs a build of the same configuration without the facades.
|
|
1807
|
-
*
|
|
1808
|
-
*
|
|
1956
|
+
* The client build first runs a build of the same configuration without the facades. The first
|
|
1957
|
+
* build keeps every export of each module of a provided package that it includes, as the facades
|
|
1958
|
+
* make the client build keep them. A package qualifies where it states which of its files have
|
|
1959
|
+
* side effects. The client build then builds each module of the first build into the chunk of the
|
|
1960
|
+
* same name, and each CommonJS module into a chunk beside it. It emits each facade as an entry
|
|
1961
|
+
* chunk that keeps its exports.
|
|
1809
1962
|
* A facade imports its specifier, and the plugin resolves the specifier from the package that
|
|
1810
1963
|
* depends on it, so the facade and the product share one module. Rolldown builds the code that
|
|
1811
1964
|
* only the facades need into chunks that only the facades import. The plugin writes
|
|
@@ -1830,7 +1983,7 @@ function provided() {
|
|
|
1830
1983
|
async buildStart() {
|
|
1831
1984
|
if (state.first || this.environment.config.consumer !== "client") return;
|
|
1832
1985
|
state.language = languageOf(state.api);
|
|
1833
|
-
state.pinned = pinnedOf(await firstBuild(this.environment.config, plugin));
|
|
1986
|
+
state.pinned = pinnedOf(await firstBuild(this.environment.config, plugin, keptPackages(state.packages)));
|
|
1834
1987
|
for (const facade of facadesOf(state.packages)) this.emitFile(facade);
|
|
1835
1988
|
},
|
|
1836
1989
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stealthscale/vite-plugin-product",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "Composes a product from its plugins while it builds: checks every plugin against the others, resolves the product, and serves it as virtual:product.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"plugins",
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
"@stealthscale/testing-config": "^0.6.0",
|
|
44
44
|
"@stealthscale/vite-config": "^0.8.0",
|
|
45
45
|
"@stealthscale/vite-config-typescript": "^0.3.0",
|
|
46
|
-
"@stealthscale/vite-plugin-base": "^0.
|
|
47
|
-
"@stealthscale/vite-plugin-i18n": "^0.
|
|
46
|
+
"@stealthscale/vite-plugin-base": "^0.5.1",
|
|
47
|
+
"@stealthscale/vite-plugin-i18n": "^0.4.0",
|
|
48
48
|
"@types/node": "^26.6",
|
|
49
49
|
"@vitest/coverage-v8": "5.0.3",
|
|
50
50
|
"publint": "^0.3",
|
|
@@ -54,8 +54,8 @@
|
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
56
|
"@stealthscale/sdk-core": "^0.3.0",
|
|
57
|
-
"@stealthscale/vite-plugin-base": "^0.
|
|
58
|
-
"@stealthscale/vite-plugin-i18n": "^0.
|
|
57
|
+
"@stealthscale/vite-plugin-base": "^0.5.1",
|
|
58
|
+
"@stealthscale/vite-plugin-i18n": "^0.4.0",
|
|
59
59
|
"vite": "^8.3"
|
|
60
60
|
},
|
|
61
61
|
"engines": {
|