optica-core 0.2.0 → 0.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "optica-core",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Shared frontend core of the Optica viewers",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "type": "module",
@@ -16,11 +16,18 @@
16
16
  ".": "./src/index.ts",
17
17
  "./ui/*": "./src/components/ui/*/index.ts",
18
18
  "./icons/*": "./src/components/icons/*.vue",
19
- "./assets/*": "./src/assets/*"
19
+ "./assets/*": "./src/assets/*",
20
+ "./vite": {
21
+ "types": "./vite/index.d.ts",
22
+ "default": "./vite/index.js"
23
+ }
20
24
  },
21
25
  "scripts": {
22
26
  "type-check": "vue-tsc --noEmit -p tsconfig.json",
23
- "test": "vitest run"
27
+ "test": "vitest run",
28
+ "push": "npm version patch && git push",
29
+ "push-minor": "npm version minor && git push",
30
+ "push-major": "npm version major && git push"
24
31
  },
25
32
  "peerDependencies": {
26
33
  "@phosphor-icons/vue": "^2.2.1",
@@ -0,0 +1,14 @@
1
+ import type { ManualChunkMeta } from 'rollup'
2
+
3
+ export interface ManualChunksOptions {
4
+ /** groups smaller than this (in bytes of source) are packed into vendor chunks, default 100 KiB */
5
+ minGroupSize?: number
6
+ /** maximum size (in bytes of source) of a vendor chunk, default 500 KiB */
7
+ maxVendorSize?: number
8
+ /** package.json whose dependencies are the direct dependencies, default `<cwd>/package.json` */
9
+ packageJson?: string
10
+ }
11
+
12
+ export function createManualChunks(
13
+ options?: ManualChunksOptions,
14
+ ): (id: string, meta: ManualChunkMeta) => string | undefined
package/vite/index.js ADDED
@@ -0,0 +1,83 @@
1
+ // Build helpers for the vite.config.ts of the Optica plugins.
2
+ // Plain JS (+ index.d.ts): Node loads it from node_modules when Vite reads the config, and cannot strip types there.
3
+ import { readFileSync } from 'node:fs'
4
+ import { resolve } from 'node:path'
5
+
6
+ const packageName = (id) => {
7
+ if (!id.includes('node_modules/')) return undefined
8
+ const parts = id.split('node_modules/').pop().split('/')
9
+ return parts[0].startsWith('@') ? `${parts[0]}/${parts[1]}` : parts[0]
10
+ }
11
+
12
+ // Vendor chunking: every package of node_modules is grouped with the direct dependency
13
+ // (from package.json) that imports it, e.g. decimal.js goes with mathjs.
14
+ // Groups smaller than minGroupSize are then packed together into "vendor-N" chunks of at most maxVendorSize.
15
+ // Sizes are measured on the sources before tree-shaking, so they overestimate the output.
16
+ export const createManualChunks = ({
17
+ minGroupSize = 100 * 1024,
18
+ maxVendorSize = 500 * 1024,
19
+ packageJson = resolve(process.cwd(), 'package.json'),
20
+ } = {}) => {
21
+ const directDeps = new Set(Object.keys(JSON.parse(readFileSync(packageJson, 'utf-8')).dependencies ?? {}))
22
+ let chunkOfPackage
23
+
24
+ const computeChunks = ({ getModuleIds, getModuleInfo }) => {
25
+ const modulesOfPackage = new Map()
26
+ for (const id of getModuleIds()) {
27
+ const pkg = packageName(id)
28
+ if (pkg) modulesOfPackage.set(pkg, [...(modulesOfPackage.get(pkg) ?? []), id])
29
+ }
30
+
31
+ // walk up the importers until reaching a direct dependency or the app code
32
+ const ownersOf = (pkg) => {
33
+ const owners = new Set()
34
+ const visited = new Set()
35
+ const queue = [...modulesOfPackage.get(pkg)]
36
+ while (queue.length) {
37
+ const id = queue.pop()
38
+ if (visited.has(id)) continue
39
+ visited.add(id)
40
+ const info = getModuleInfo(id)
41
+ for (const importer of [...(info?.importers ?? []), ...(info?.dynamicImporters ?? [])]) {
42
+ const importerPkg = packageName(importer)
43
+ if (!importerPkg) owners.add(pkg)
44
+ else if (importerPkg === pkg) queue.push(importer)
45
+ else if (directDeps.has(importerPkg)) owners.add(importerPkg)
46
+ else queue.push(importer)
47
+ }
48
+ }
49
+ return owners
50
+ }
51
+
52
+ const groupOfPackage = new Map()
53
+ const groupSize = new Map()
54
+ for (const [pkg, ids] of modulesOfPackage) {
55
+ const owners = directDeps.has(pkg) ? new Set([pkg]) : ownersOf(pkg)
56
+ const group = owners.size === 1 ? [...owners][0] : 'shared'
57
+ groupOfPackage.set(pkg, group)
58
+ const size = ids.reduce((total, id) => total + (getModuleInfo(id)?.code?.length ?? 0), 0)
59
+ groupSize.set(group, (groupSize.get(group) ?? 0) + size)
60
+ }
61
+
62
+ // big groups get their own chunk, small ones are packed into vendor chunks
63
+ const chunkOfGroup = new Map()
64
+ const vendorSizes = []
65
+ const smallGroups = [...groupSize].filter(([group, size]) => group === 'shared' || size < minGroupSize)
66
+ for (const [group] of groupSize) chunkOfGroup.set(group, group.replace('/', '-'))
67
+ for (const [group, size] of smallGroups.sort((a, b) => b[1] - a[1])) {
68
+ let index = vendorSizes.findIndex((total) => total + size <= maxVendorSize)
69
+ if (index === -1) index = vendorSizes.push(0) - 1
70
+ vendorSizes[index] += size
71
+ chunkOfGroup.set(group, `vendor-${index}`)
72
+ }
73
+
74
+ return new Map([...groupOfPackage].map(([pkg, group]) => [pkg, chunkOfGroup.get(group)]))
75
+ }
76
+
77
+ return (id, meta) => {
78
+ const pkg = packageName(id)
79
+ if (!pkg) return undefined
80
+ chunkOfPackage ??= computeChunks(meta)
81
+ return chunkOfPackage.get(pkg)
82
+ }
83
+ }
Binary file