@stealthscale/vite-plugin-product 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md 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 second build places each recorded module in the chunk of the same name,
232
- and each recorded CommonJS module in a chunk beside it, named with `-cjs`. Rolldown builds the
233
- code that only the entries need into chunks that only the entries import.
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
@@ -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.0","bom-ref":"pkg:npm/%40stealthscale/vite-plugin-base@0.5.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.5.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.2","bom-ref":"pkg:npm/%40stealthscale/vite-plugin-i18n@0.3.2","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.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-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.1","bom-ref":"pkg:npm/%40stealthscale/vite-plugin-product@0.3.1","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.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-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.1"}]}
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. It then
111
- * builds each module of that first build into the chunk of the same name, and each CommonJS
112
- * module into a chunk beside it. It emits each facade as an entry chunk that keeps its exports.
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,7 +3,7 @@ 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";
@@ -1417,108 +1417,6 @@ function facadeOf(specifier, shape) {
1417
1417
  ].join("\n");
1418
1418
  }
1419
1419
  //#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
1420
  //#region src/provided/packages.ts
1523
1421
  /**
1524
1422
  * Lists the packages a page provides to the releases it loads, and the specifiers of each.
@@ -1666,6 +1564,231 @@ function importerOf(provided, specifier) {
1666
1564
  return owner === void 0 ? void 0 : join(owner.from, "package.json");
1667
1565
  }
1668
1566
  //#endregion
1567
+ //#region src/provided/kept.ts
1568
+ /**
1569
+ * Makes a product's first build keep every export of each module of a provided package that the
1570
+ * build includes.
1571
+ *
1572
+ * @remarks
1573
+ * A facade keeps every export of its specifier's module, so the second build keeps code that the
1574
+ * first build removed from a module the product uses. A published package bundles its components
1575
+ * into few modules, and the code that the first build removed imports modules that the first
1576
+ * build left out. Those modules have no pin, so rolldown builds them into a chunk of their own,
1577
+ * and that chunk imports the pinned chunk that imports it. In such a cycle a module can read a
1578
+ * binding of the other chunk before that chunk has run. The first build therefore appends to each
1579
+ * module of a provided package a statement that passes the module's namespace to a global hook.
1580
+ * The statement keeps every export of a module that the build includes, so the first build places
1581
+ * the modules that those exports import. The statement adds no module to the build, because a
1582
+ * package that states its side effects lets the build leave out a module whose exports nothing
1583
+ * uses.
1584
+ */
1585
+ /**
1586
+ * The extensions of an ES module in any package.
1587
+ */
1588
+ const MODULES = /* @__PURE__ */ new Set([".mjs", ".mts"]);
1589
+ /**
1590
+ * The extensions of an ES module in a package that states `"type": "module"`.
1591
+ */
1592
+ const TYPED = /* @__PURE__ */ new Set([
1593
+ ".js",
1594
+ ".jsx",
1595
+ ".ts",
1596
+ ".tsx"
1597
+ ]);
1598
+ /**
1599
+ * The key of the global function that the kept statement passes a module's namespace to. No page
1600
+ * defines the function, because no page loads the first build's output.
1601
+ */
1602
+ const HOOK = "stealth.kept";
1603
+ /**
1604
+ * Returns the patterns of a package's files that have side effects, or undefined where the
1605
+ * package does not state them.
1606
+ */
1607
+ function effectsOf(sideEffects) {
1608
+ if (sideEffects === false) return [];
1609
+ if (!Array.isArray(sideEffects)) return void 0;
1610
+ return sideEffects.filter((pattern) => typeof pattern === "string");
1611
+ }
1612
+ /**
1613
+ * Returns the provided packages whose modules the first build keeps whole: each installed package
1614
+ * whose manifest states which of its files have side effects.
1615
+ *
1616
+ * @param packages - The packages the product provides.
1617
+ */
1618
+ function keptPackages(packages) {
1619
+ return packages.flatMap(({ from, name }) => {
1620
+ const directory = packageAt(name, from);
1621
+ const manifest = directory === void 0 ? void 0 : manifestAt(directory);
1622
+ const effects = effectsOf(manifest?.["sideEffects"]);
1623
+ return directory === void 0 || effects === void 0 ? [] : [{
1624
+ directory,
1625
+ effects,
1626
+ typed: manifest?.["type"] === "module"
1627
+ }];
1628
+ });
1629
+ }
1630
+ /**
1631
+ * Returns true where a pattern of a package's `sideEffects` list matches a file at a path relative
1632
+ * to the package.
1633
+ *
1634
+ * @remarks
1635
+ * A pattern without a slash matches the file's name in any directory, as bundlers read the list.
1636
+ */
1637
+ function affects(pattern, path) {
1638
+ return matchesGlob(path, pattern.includes("/") ? pattern.replace(/^\.\//u, "") : `**/${pattern}`);
1639
+ }
1640
+ /**
1641
+ * Returns true for a module whose exports the first build keeps whole: an ES module file of a kept
1642
+ * package that no side-effect pattern of the package matches.
1643
+ *
1644
+ * @remarks
1645
+ * A file below a `node_modules` directory inside the package belongs to another package.
1646
+ * @param id - The module's id.
1647
+ * @param packages - The packages whose modules the first build keeps whole.
1648
+ */
1649
+ function isKept(id, packages) {
1650
+ const owner = isAbsolute(id) ? packages.find(({ directory }) => id.startsWith(`${directory}${sep}`)) : void 0;
1651
+ if (owner === void 0) return false;
1652
+ const path = relative(owner.directory, id);
1653
+ const extension = extname(id);
1654
+ return (MODULES.has(extension) || owner.typed && TYPED.has(extension)) && !path.split(sep).includes("node_modules") && !owner.effects.some((pattern) => affects(pattern, path));
1655
+ }
1656
+ /**
1657
+ * Returns a module's code with the statement that keeps its exports appended: a namespace import of
1658
+ * the module's own file, passed to a global hook.
1659
+ *
1660
+ * @param code - The module's code.
1661
+ * @param id - The module's id, the absolute path of its file.
1662
+ */
1663
+ function keptSourceOf(code, id) {
1664
+ return [
1665
+ code,
1666
+ `import * as __stealthKept from ${quoted(`./${basename(id)}`)};`,
1667
+ `globalThis[Symbol.for(${quoted(HOOK)})]?.(__stealthKept);`,
1668
+ ""
1669
+ ].join("\n");
1670
+ }
1671
+ //#endregion
1672
+ //#region src/provided/pinned.ts
1673
+ /**
1674
+ * Returns a map from the id of each module of the first build to the name of its chunk.
1675
+ *
1676
+ * @remarks
1677
+ * The modules of a static entry's chunk have no pin. The second chunk of one name in file name
1678
+ * order takes the name with `-2` appended, and the third takes it with `-3` appended.
1679
+ * @param chunks - The chunks of the first build.
1680
+ */
1681
+ function pinnedOf(chunks) {
1682
+ const counts = /* @__PURE__ */ new Map();
1683
+ const pinned = /* @__PURE__ */ new Map();
1684
+ const ordered = chunks.filter(({ isEntry }) => !isEntry).toSorted((one, two) => one.fileName.localeCompare(two.fileName));
1685
+ for (const { modules, name } of ordered) {
1686
+ const count = (counts.get(name) ?? 0) + 1;
1687
+ const pin = count === 1 ? name : `${name}-${String(count)}`;
1688
+ counts.set(name, count);
1689
+ for (const id of Object.keys(modules)) pinned.set(id, pin);
1690
+ }
1691
+ return pinned;
1692
+ }
1693
+ /**
1694
+ * Returns the code-splitting group that places each pinned module in the second build.
1695
+ *
1696
+ * @remarks
1697
+ * A pinned chunk can import a chunk of the facades' code that imports it back. Rolldown defines a
1698
+ * CommonJS module's wrapper at the top level of its chunk, and an ES module that imports it calls
1699
+ * the wrapper at its own top level. In such a cycle a chunk can call a wrapper that is not
1700
+ * defined yet. The group builds each pin's CommonJS modules into a chunk of their own. As long as
1701
+ * those modules require only CommonJS modules, that chunk imports only rolldown's runtime and
1702
+ * other such chunks. It then runs before every chunk that calls its wrappers.
1703
+ * @param pins - Returns a map from the id of each module of the first build to its chunk once the
1704
+ * first build has run.
1705
+ */
1706
+ function pinnedGroup(pins) {
1707
+ return {
1708
+ debugName: "pinned",
1709
+ name: (id, chunking) => {
1710
+ const pin = pins()?.get(id);
1711
+ if (pin === void 0) return null;
1712
+ return chunking.getModuleInfo(id)?.inputFormat === "cjs" ? `${pin}-cjs` : pin;
1713
+ }
1714
+ };
1715
+ }
1716
+ //#endregion
1717
+ //#region src/provided/first.ts
1718
+ /**
1719
+ * Runs a product's first build: the build's own configuration without the facades, written
1720
+ * nowhere, whose chunks the second build pins the product's modules to.
1721
+ */
1722
+ /**
1723
+ * Name of the plugin that marks the first build, which leaves the facades out.
1724
+ */
1725
+ const FIRST_BUILD = "stealth:provided-first";
1726
+ /**
1727
+ * Returns true where a configuration's plugins mark the first build.
1728
+ *
1729
+ * @param plugins - The resolved plugins of a build.
1730
+ */
1731
+ function isFirstBuild(plugins) {
1732
+ return plugins.some(({ name }) => name === FIRST_BUILD);
1733
+ }
1734
+ /**
1735
+ * Returns a plugin option with every nested list flattened into one list.
1736
+ */
1737
+ function flattened(option) {
1738
+ return Array.isArray(option) ? option.flatMap((one) => flattened(one)) : [option];
1739
+ }
1740
+ /**
1741
+ * Returns the plugins a caller passed inline, with the second build's own facade plugin left out.
1742
+ */
1743
+ function inlinePlugins(plugins, own) {
1744
+ return (plugins ?? []).flatMap((option) => flattened(option)).filter((one) => one !== own);
1745
+ }
1746
+ /**
1747
+ * Returns the plugin that marks the first build and keeps every export of each module of a kept
1748
+ * package.
1749
+ */
1750
+ function markOf(kept) {
1751
+ return {
1752
+ name: FIRST_BUILD,
1753
+ /**
1754
+ * Appends the statement that keeps every export to each module of a kept package, and leaves
1755
+ * every other module alone.
1756
+ */
1757
+ transform(code, id) {
1758
+ return isKept(id, kept) ? keptSourceOf(code, id) : null;
1759
+ }
1760
+ };
1761
+ }
1762
+ /**
1763
+ * Returns the chunks of the first build of the configuration a second build resolved.
1764
+ *
1765
+ * @remarks
1766
+ * The first build reads the same configuration file and the same inline configuration, with the
1767
+ * plugin that marks it, without watching and without writing. A facade plugin of the first build
1768
+ * reads the mark and adds nothing. The plugin that marks the build keeps every export of each
1769
+ * module of a kept package that the build includes, as the facades make the second build keep
1770
+ * them. The first build therefore also places the modules that those exports import.
1771
+ * @param config - The second build's configuration file, inline configuration, mode and root.
1772
+ * @param own - The second build's facade plugin, which a caller may have passed inline.
1773
+ * @param kept - The provided packages whose modules the first build keeps whole.
1774
+ */
1775
+ async function firstBuild(config, own, kept) {
1776
+ const { configFile, inlineConfig, mode, root } = config;
1777
+ return [await build({
1778
+ ...inlineConfig,
1779
+ build: {
1780
+ ...inlineConfig.build,
1781
+ watch: null,
1782
+ write: false
1783
+ },
1784
+ configFile: configFile ?? false,
1785
+ logLevel: "silent",
1786
+ mode,
1787
+ plugins: [...inlinePlugins(inlineConfig.plugins, own), markOf(kept)],
1788
+ root
1789
+ })].flat().flatMap(({ output }) => output).filter((file) => file.type === "chunk");
1790
+ }
1791
+ //#endregion
1669
1792
  //#region src/provided/manifest.ts
1670
1793
  /**
1671
1794
  * Returns the paths of some chunks and of every chunk that they import statically. The given
@@ -1803,9 +1926,12 @@ async function facadeSourceOf(context, packages, id) {
1803
1926
  * Creates the plugin that provides the product's shared modules to the releases its page loads.
1804
1927
  *
1805
1928
  * @remarks
1806
- * The client build first runs a build of the same configuration without the facades. It then
1807
- * builds each module of that first build into the chunk of the same name, and each CommonJS
1808
- * module into a chunk beside it. It emits each facade as an entry chunk that keeps its exports.
1929
+ * The client build first runs a build of the same configuration without the facades. The first
1930
+ * build keeps every export of each module of a provided package that it includes, as the facades
1931
+ * make the client build keep them. A package qualifies where it states which of its files have
1932
+ * side effects. The client build then builds each module of the first build into the chunk of the
1933
+ * same name, and each CommonJS module into a chunk beside it. It emits each facade as an entry
1934
+ * chunk that keeps its exports.
1809
1935
  * A facade imports its specifier, and the plugin resolves the specifier from the package that
1810
1936
  * depends on it, so the facade and the product share one module. Rolldown builds the code that
1811
1937
  * only the facades need into chunks that only the facades import. The plugin writes
@@ -1830,7 +1956,7 @@ function provided() {
1830
1956
  async buildStart() {
1831
1957
  if (state.first || this.environment.config.consumer !== "client") return;
1832
1958
  state.language = languageOf(state.api);
1833
- state.pinned = pinnedOf(await firstBuild(this.environment.config, plugin));
1959
+ state.pinned = pinnedOf(await firstBuild(this.environment.config, plugin, keptPackages(state.packages)));
1834
1960
  for (const facade of facadesOf(state.packages)) this.emitFile(facade);
1835
1961
  },
1836
1962
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stealthscale/vite-plugin-product",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
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.4.0",
47
- "@stealthscale/vite-plugin-i18n": "^0.3.1",
46
+ "@stealthscale/vite-plugin-base": "^0.5.0",
47
+ "@stealthscale/vite-plugin-i18n": "^0.3.2",
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.4.0",
58
- "@stealthscale/vite-plugin-i18n": "^0.3.1",
57
+ "@stealthscale/vite-plugin-base": "^0.5.0",
58
+ "@stealthscale/vite-plugin-i18n": "^0.3.2",
59
59
  "vite": "^8.3"
60
60
  },
61
61
  "engines": {