From a3da5a9579253520aa21e140df085e88bd665346 Mon Sep 17 00:00:00 2001 From: Iwo Plaza Date: Sun, 17 Aug 2025 15:37:12 +0200 Subject: [PATCH 01/11] Bundle bundle --- apps/typegpu-docs/astro.config.mjs | 6 ++ apps/typegpu-docs/package.json | 1 + apps/typegpu-docs/public/service-worker.js | 32 ++++++++ .../components/translator/TranslatorApp.tsx | 11 +++ .../src/components/translator/lib/rolldown.ts | 78 +++++++++++++++++++ package.json | 7 +- pnpm-lock.yaml | 77 +++++++++++++++++- 7 files changed, 210 insertions(+), 2 deletions(-) create mode 100644 apps/typegpu-docs/public/service-worker.js create mode 100644 apps/typegpu-docs/src/components/translator/lib/rolldown.ts diff --git a/apps/typegpu-docs/astro.config.mjs b/apps/typegpu-docs/astro.config.mjs index 1dc05a6d8..0da077aaa 100644 --- a/apps/typegpu-docs/astro.config.mjs +++ b/apps/typegpu-docs/astro.config.mjs @@ -26,6 +26,12 @@ export default defineConfig({ site: 'https://docs.swmansion.com', base: 'TypeGPU', vite: { + define: { + 'process.env.NODE_DEBUG_NATIVE': '""', + }, + optimizeDeps: { + exclude: ['@rolldown/browser'], + }, // Allowing query params, for invalidation plugins: [ wasm(), diff --git a/apps/typegpu-docs/package.json b/apps/typegpu-docs/package.json index 19f46dcbe..d5af523f0 100644 --- a/apps/typegpu-docs/package.json +++ b/apps/typegpu-docs/package.json @@ -22,6 +22,7 @@ "@monaco-editor/react": "^4.7.0", "@radix-ui/react-select": "^2.2.5", "@radix-ui/react-slider": "^1.3.5", + "@rolldown/browser": "1.0.0-beta.32", "@stackblitz/sdk": "^1.11.0", "@tailwindcss/vite": "^4.1.11", "@typegpu/color": "workspace:*", diff --git a/apps/typegpu-docs/public/service-worker.js b/apps/typegpu-docs/public/service-worker.js new file mode 100644 index 000000000..333d6ac89 --- /dev/null +++ b/apps/typegpu-docs/public/service-worker.js @@ -0,0 +1,32 @@ +// This service worker is responsible for intercepting fetch requests to +// assets hosted on the same origin, and attaching CORS headers that +// allow SharedArrayBuffer to function (required by @rolldown/browser). + +self.addEventListener('fetch', (event) => { + if ( + event.request.cache === 'only-if-cached' && + event.request.mode !== 'same-origin' + ) { + return; + } + + event.respondWith( + fetch(event.request) + .then((response) => { + const newHeaders = new Headers(response.headers); + newHeaders.set('Cross-Origin-Embedder-Policy', 'require-corp'); + newHeaders.set('Cross-Origin-Opener-Policy', 'same-origin'); + + const moddedResponse = new Response(response.body, { + status: response.status, + statusText: response.statusText, + headers: newHeaders, + }); + + return moddedResponse; + }) + .catch((e) => { + console.error(e); + }), + ); +}); diff --git a/apps/typegpu-docs/src/components/translator/TranslatorApp.tsx b/apps/typegpu-docs/src/components/translator/TranslatorApp.tsx index 6d6d85b1e..ae5f2db8f 100644 --- a/apps/typegpu-docs/src/components/translator/TranslatorApp.tsx +++ b/apps/typegpu-docs/src/components/translator/TranslatorApp.tsx @@ -19,6 +19,7 @@ import { wgslCodeAtom, } from './lib/translatorStore.ts'; import { useAutoCompile } from './lib/useAutoCompile.ts'; +import { main } from './lib/rolldown.ts'; interface EditorSectionProps { id: string; @@ -84,6 +85,16 @@ export default function TranslatorApp() { initialize(); }, [initialize]); + useEffect(() => { + (async () => { + const result = await main({ + 'index.ts': `console.log('Bruh')`, + }, ['index.ts']); + + console.log(result); + })(); + }, []); + const handleEditorLoaded = () => setEditorLoaded(false); const isTgslMode = mode === TRANSLATOR_MODES.TGSL; diff --git a/apps/typegpu-docs/src/components/translator/lib/rolldown.ts b/apps/typegpu-docs/src/components/translator/lib/rolldown.ts new file mode 100644 index 000000000..b7f5fc481 --- /dev/null +++ b/apps/typegpu-docs/src/components/translator/lib/rolldown.ts @@ -0,0 +1,78 @@ +import { resolve } from 'pathe'; +import type { InputOptions, OutputOptions } from '@rolldown/browser'; + +export interface BundleResult { + output: Record; + warnings?: string[] | undefined; +} + +export interface SourceFile { + filename: string; + code: string; + isEntry?: boolean; +} + +export type FileMap = Record; + +export async function main( + files: FileMap, + entries: string[], + config: InputOptions & { output?: OutputOptions | undefined } = {}, +): Promise { + const rolldown = await import('@rolldown/browser'); + + const warnings: string[] = []; + + const inputOptions: InputOptions = { + input: entries, + cwd: '/', + onLog(level, log, logger) { + if (level === 'warn') { + warnings.push(String(log)); + } else { + logger(level, log); + } + }, + ...config, + plugins: [ + // Virtual file system plugin + { + name: 'virtual-fs', + resolveId(source, importer) { + if (source[0] === '/' || source[0] === '.') { + return resolve(importer || '/', '..', source); + } + }, + load(id) { + if (id[0] !== '/') return; + const filename = id.slice(1); + return files[filename]; + }, + }, + ...(Array.isArray(config?.plugins) + ? config.plugins + : [config?.plugins].filter(Boolean)), + ], + }; + + const outputOptions: OutputOptions = { + format: 'esm', + ...config?.output, + }; + + const bundle = await rolldown.rolldown(inputOptions); + const result = await bundle.generate(outputOptions); + + const output = Object.fromEntries( + result.output.map((chunk) => + chunk.type === 'chunk' + ? [chunk.fileName, chunk.code] + : [chunk.fileName, chunk.source] + ), + ); + + return { + output, + warnings, + }; +} diff --git a/package.json b/package.json index b00db77c3..2c76c5f60 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,11 @@ "type": "git", "url": "git+https://github.com/software-mansion/TypeGPU.git" }, - "keywords": ["webgpu", "wgpu", "wgsl"], + "keywords": [ + "webgpu", + "wgpu", + "wgsl" + ], "bugs": { "url": "https://github.com/software-mansion/TypeGPU/issues" }, @@ -52,6 +56,7 @@ "pnpm": { "onlyBuiltDependencies": [ "@biomejs/biome", + "@rolldown/browser", "@tailwindcss/oxide", "esbuild", "msw", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5b78f0fd8..dc8ab47cb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -106,7 +106,7 @@ importers: devDependencies: '@types/bun': specifier: latest - version: 1.2.19(@types/react@19.1.8) + version: 1.2.20(@types/react@19.1.8) apps/infra-benchmarks: devDependencies: @@ -152,6 +152,9 @@ importers: '@radix-ui/react-slider': specifier: ^1.3.5 version: 1.3.5(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@rolldown/browser': + specifier: 1.0.0-beta.32 + version: 1.0.0-beta.32 '@stackblitz/sdk': specifier: ^1.11.0 version: 1.11.0 @@ -929,12 +932,21 @@ packages: '@emmetio/stream-reader@2.2.0': resolution: {integrity: sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw==} + '@emnapi/core@1.4.5': + resolution: {integrity: sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q==} + '@emnapi/runtime@1.4.3': resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==} '@emnapi/runtime@1.4.4': resolution: {integrity: sha512-hHyapA4A3gPaDCNfiqyZUStTMqIkKRshqPIuDOXv1hcBnD4U3l8cP0T1HMCfGRxQ6V64TGCcoswChANyOAwbQg==} + '@emnapi/runtime@1.4.5': + resolution: {integrity: sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==} + + '@emnapi/wasi-threads@1.0.4': + resolution: {integrity: sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g==} + '@esbuild/aix-ppc64@0.24.2': resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==} engines: {node: '>=18'} @@ -1764,6 +1776,9 @@ packages: resolution: {integrity: sha512-B9nHSJYtsv79uo7QdkZ/b/WoKm20IkVSmTc/WCKarmDtFwM0dRx2ouEniqwNkzCSLn3fydzKmnMzjtfdOWt3VQ==} engines: {node: '>=18'} + '@napi-rs/wasm-runtime@1.0.3': + resolution: {integrity: sha512-rZxtMsLwjdXkMUGC3WwsPwLNVqVqnTJT6MNIB6e+5fhMcSCPP0AOsNWuMQ5mdCq6HNjs/ZeWAEchpqeprqBD2Q==} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -1848,6 +1863,10 @@ packages: '@oslojs/encoding@1.1.0': resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==} + '@oxc-project/runtime@0.81.0': + resolution: {integrity: sha512-zm/LDVOq9FEmHiuM8zO4DWirv0VP2Tv2VsgaiHby9nvpq+FVrcqNYgv+TysLKOITQXWZj/roluTxFvpkHP0Iuw==} + engines: {node: '>=6.9.0'} + '@pagefind/darwin-arm64@1.3.0': resolution: {integrity: sha512-365BEGl6ChOsauRjyVpBjXybflXAOvoMROw3TucAROHIcdBvXk9/2AmEvGFU0r75+vdQI4LJdJdpH4Y6Yqaj4A==} cpu: [arm64] @@ -2162,6 +2181,10 @@ packages: '@radix-ui/rect@1.1.1': resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} + '@rolldown/browser@1.0.0-beta.32': + resolution: {integrity: sha512-g9Cj/Kn3gO//7eT9RRLN7Zb6juFqSJJjVfm3Mv1aivZW5a66VSEXuQnkCHPsTST4qVnrRXnyGjUk5ftVTKk80A==} + hasBin: true + '@rolldown/pluginutils@1.0.0-beta.19': resolution: {integrity: sha512-3FL3mnMbPu0muGOCaKAhhFEYmqv9eTfPSJRJmANrCwtgK8VuxpsZDGK+m0LYAGoyO8+0j5uRe4PeyPDK1yA/hA==} @@ -2467,6 +2490,9 @@ packages: resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} + '@tybys/wasm-util@0.10.0': + resolution: {integrity: sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==} + '@types/acorn@4.0.6': resolution: {integrity: sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==} @@ -2491,6 +2517,9 @@ packages: '@types/bun@1.2.19': resolution: {integrity: sha512-d9ZCmrH3CJ2uYKXQIUuZ/pUnTqIvLDS0SK7pFmbx8ma+ziH/FRMoAq5bYpRG7y+w1gl+HgyNZbtqgMq4W4e2Lg==} + '@types/bun@1.2.20': + resolution: {integrity: sha512-dX3RGzQ8+KgmMw7CsW4xT5ITBSCrSbfHc36SNT31EOUg/LA9JWq0VDdEXDRSe1InVWpd2yLUM1FUF/kEOyTzYA==} + '@types/chai@5.2.2': resolution: {integrity: sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==} @@ -2877,6 +2906,11 @@ packages: peerDependencies: '@types/react': ^19 + bun-types@1.2.20: + resolution: {integrity: sha512-pxTnQYOrKvdOwyiyd/7sMt9yFOenN004Y6O4lCcCUoKVej48FS5cvTw9geRaEcB9TsDZaJKAxPTVvi8tFsVuXA==} + peerDependencies: + '@types/react': ^19 + bundle-require@5.1.0: resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -6563,6 +6597,11 @@ snapshots: '@emmetio/stream-reader@2.2.0': {} + '@emnapi/core@1.4.5': + dependencies: + '@emnapi/wasi-threads': 1.0.4 + tslib: 2.8.1 + '@emnapi/runtime@1.4.3': dependencies: tslib: 2.8.1 @@ -6573,6 +6612,14 @@ snapshots: tslib: 2.8.1 optional: true + '@emnapi/runtime@1.4.5': + dependencies: + tslib: 2.8.1 + + '@emnapi/wasi-threads@1.0.4': + dependencies: + tslib: 2.8.1 + '@esbuild/aix-ppc64@0.24.2': optional: true @@ -7173,6 +7220,12 @@ snapshots: strict-event-emitter: 0.5.1 optional: true + '@napi-rs/wasm-runtime@1.0.3': + dependencies: + '@emnapi/core': 1.4.5 + '@emnapi/runtime': 1.4.5 + '@tybys/wasm-util': 0.10.0 + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -7277,6 +7330,8 @@ snapshots: '@oslojs/encoding@1.1.0': {} + '@oxc-project/runtime@0.81.0': {} + '@pagefind/darwin-arm64@1.3.0': optional: true @@ -7549,6 +7604,11 @@ snapshots: '@radix-ui/rect@1.1.1': {} + '@rolldown/browser@1.0.0-beta.32': + dependencies: + '@napi-rs/wasm-runtime': 1.0.3 + '@oxc-project/runtime': 0.81.0 + '@rolldown/pluginutils@1.0.0-beta.19': {} '@rollup/plugin-alias@5.1.1(rollup@4.34.8)': @@ -7800,6 +7860,10 @@ snapshots: '@trysound/sax@0.2.0': {} + '@tybys/wasm-util@0.10.0': + dependencies: + tslib: 2.8.1 + '@types/acorn@4.0.6': dependencies: '@types/estree': 1.0.8 @@ -7842,6 +7906,12 @@ snapshots: transitivePeerDependencies: - '@types/react' + '@types/bun@1.2.20(@types/react@19.1.8)': + dependencies: + bun-types: 1.2.20(@types/react@19.1.8) + transitivePeerDependencies: + - '@types/react' + '@types/chai@5.2.2': dependencies: '@types/deep-eql': 4.0.2 @@ -8392,6 +8462,11 @@ snapshots: '@types/node': 24.1.0 '@types/react': 19.1.8 + bun-types@1.2.20(@types/react@19.1.8): + dependencies: + '@types/node': 24.1.0 + '@types/react': 19.1.8 + bundle-require@5.1.0(esbuild@0.25.6): dependencies: esbuild: 0.25.6 From 029491f2315c03f4209562842966fc74e2af2aff Mon Sep 17 00:00:00 2001 From: Iwo Plaza Date: Mon, 18 Aug 2025 18:41:31 +0200 Subject: [PATCH 02/11] Some updates --- apps/typegpu-docs/astro.config.mjs | 6 + apps/typegpu-docs/public/coi-serviceworker.js | 176 ++++++++++++++++++ apps/typegpu-docs/public/service-worker.js | 32 ---- .../components/translator/TranslatorApp.tsx | 11 -- .../src/components/translator/lib/rolldown.ts | 14 +- .../components/translator/lib/tgslExecutor.ts | 13 ++ .../typegpu-docs/src/layouts/PageLayout.astro | 123 ++++++------ 7 files changed, 266 insertions(+), 109 deletions(-) create mode 100644 apps/typegpu-docs/public/coi-serviceworker.js delete mode 100644 apps/typegpu-docs/public/service-worker.js diff --git a/apps/typegpu-docs/astro.config.mjs b/apps/typegpu-docs/astro.config.mjs index 0da077aaa..21d140e3d 100644 --- a/apps/typegpu-docs/astro.config.mjs +++ b/apps/typegpu-docs/astro.config.mjs @@ -32,6 +32,11 @@ export default defineConfig({ optimizeDeps: { exclude: ['@rolldown/browser'], }, + server: { + fs: { + allow: ['..'] + } + }, // Allowing query params, for invalidation plugins: [ wasm(), @@ -48,6 +53,7 @@ export default defineConfig({ ssr: { noExternal: [ 'wgsl-wasm-transpiler-bundler', + '@rolldown/browser', ], }, }, diff --git a/apps/typegpu-docs/public/coi-serviceworker.js b/apps/typegpu-docs/public/coi-serviceworker.js new file mode 100644 index 000000000..92b87f432 --- /dev/null +++ b/apps/typegpu-docs/public/coi-serviceworker.js @@ -0,0 +1,176 @@ +/*! coi-serviceworker v0.1.7 - Guido Zuidhof and contributors, licensed under MIT */ + +// This service worker is responsible for intercepting fetch requests to +// assets hosted on the same origin, and attaching CORS headers that +// allow SharedArrayBuffer to function (required by @rolldown/browser). + +let coepCredentialless = false; +if (typeof window === 'undefined') { + self.addEventListener('install', () => self.skipWaiting()); + self.addEventListener( + 'activate', + (event) => event.waitUntil(self.clients.claim()), + ); + + self.addEventListener('message', (ev) => { + if (!ev.data) { + return; + } + + if (ev.data.type === 'deregister') { + self.registration + .unregister() + .then(() => { + return self.clients.matchAll(); + }) + .then((clients) => { + for (const client of clients) { + client.navigate(client.url); + } + }); + } else if (ev.data.type === 'coepCredentialless') { + coepCredentialless = ev.data.value; + } + }); + + self.addEventListener('fetch', (event) => { + const r = event.request; + console.log('SERVICE: Intercepting request...', r); + if (r.cache === 'only-if-cached' && r.mode !== 'same-origin') { + return; + } + + const request = (coepCredentialless && r.mode === 'no-cors') + ? new Request(r, { + credentials: 'omit', + }) + : r; + event.respondWith( + fetch(request) + .then((response) => { + if (response.status === 0) { + return response; + } + + const newHeaders = new Headers(response.headers); + newHeaders.set( + 'Cross-Origin-Embedder-Policy', + coepCredentialless ? 'credentialless' : 'require-corp', + ); + if (!coepCredentialless) { + newHeaders.set('Cross-Origin-Resource-Policy', 'cross-origin'); + } + newHeaders.set('Cross-Origin-Opener-Policy', 'same-origin'); + + return new Response(response.body, { + status: response.status, + statusText: response.statusText, + headers: newHeaders, + }); + }) + .catch((e) => console.error(e)), + ); + }); +} else { + (() => { + const reloadedBySelf = window.sessionStorage.getItem('coiReloadedBySelf'); + window.sessionStorage.removeItem('coiReloadedBySelf'); + const coepDegrading = reloadedBySelf === 'coepdegrade'; + + // You can customize the behavior of this script through a global `coi` variable. + const coi = { + shouldRegister: () => !reloadedBySelf, + shouldDeregister: () => false, + coepCredentialless: () => true, + coepDegrade: () => true, + doReload: () => window.location.reload(), + quiet: false, + ...window.coi, + }; + + const n = navigator; + const controlling = !!n.serviceWorker && !!n.serviceWorker.controller; + + // Record the failure if the page is served by serviceWorker. + if (controlling && !window.crossOriginIsolated) { + window.sessionStorage.setItem('coiCoepHasFailed', 'true'); + } + const coepHasFailed = window.sessionStorage.getItem('coiCoepHasFailed'); + + if (controlling) { + // Reload only on the first failure. + const reloadToDegrade = coi.coepDegrade() && !( + coepDegrading || window.crossOriginIsolated + ); + n.serviceWorker.controller.postMessage({ + type: 'coepCredentialless', + value: (reloadToDegrade || coepHasFailed && coi.coepDegrade()) + ? false + : coi.coepCredentialless(), + }); + if (reloadToDegrade) { + !coi.quiet && console.log('Reloading page to degrade COEP.'); + window.sessionStorage.setItem('coiReloadedBySelf', 'coepdegrade'); + coi.doReload('coepdegrade'); + } + + if (coi.shouldDeregister()) { + n.serviceWorker.controller.postMessage({ type: 'deregister' }); + } + } + + // If we're already coi: do nothing. Perhaps it's due to this script doing its job, or COOP/COEP are + // already set from the origin server. Also if the browser has no notion of crossOriginIsolated, just give up here. + if (window.crossOriginIsolated !== false || !coi.shouldRegister()) return; + + if (!window.isSecureContext) { + !coi.quiet && + console.log( + 'COOP/COEP Service Worker not registered, a secure context is required.', + ); + return; + } + + // In some environments (e.g. Firefox private mode) this won't be available + if (!n.serviceWorker) { + !coi.quiet && + console.error( + 'COOP/COEP Service Worker not registered, perhaps due to private mode.', + ); + return; + } + + n.serviceWorker.register(window.document.currentScript.src).then( + (registration) => { + !coi.quiet && + console.log( + 'COOP/COEP Service Worker registered', + registration.scope, + ); + + registration.addEventListener('updatefound', () => { + !coi.quiet && + console.log( + 'Reloading page to make use of updated COOP/COEP Service Worker.', + ); + window.sessionStorage.setItem('coiReloadedBySelf', 'updatefound'); + coi.doReload(); + }); + + // If the registration is active, but it's not controlling the page + if (registration.active && !n.serviceWorker.controller) { + !coi.quiet && + console.log( + 'Reloading page to make use of COOP/COEP Service Worker.', + ); + window.sessionStorage.setItem('coiReloadedBySelf', 'notcontrolling'); + coi.doReload(); + } + }, + (err) => { + !coi.quiet && + console.error('COOP/COEP Service Worker failed to register:', err); + }, + ); + })(); +} diff --git a/apps/typegpu-docs/public/service-worker.js b/apps/typegpu-docs/public/service-worker.js deleted file mode 100644 index 333d6ac89..000000000 --- a/apps/typegpu-docs/public/service-worker.js +++ /dev/null @@ -1,32 +0,0 @@ -// This service worker is responsible for intercepting fetch requests to -// assets hosted on the same origin, and attaching CORS headers that -// allow SharedArrayBuffer to function (required by @rolldown/browser). - -self.addEventListener('fetch', (event) => { - if ( - event.request.cache === 'only-if-cached' && - event.request.mode !== 'same-origin' - ) { - return; - } - - event.respondWith( - fetch(event.request) - .then((response) => { - const newHeaders = new Headers(response.headers); - newHeaders.set('Cross-Origin-Embedder-Policy', 'require-corp'); - newHeaders.set('Cross-Origin-Opener-Policy', 'same-origin'); - - const moddedResponse = new Response(response.body, { - status: response.status, - statusText: response.statusText, - headers: newHeaders, - }); - - return moddedResponse; - }) - .catch((e) => { - console.error(e); - }), - ); -}); diff --git a/apps/typegpu-docs/src/components/translator/TranslatorApp.tsx b/apps/typegpu-docs/src/components/translator/TranslatorApp.tsx index ae5f2db8f..6d6d85b1e 100644 --- a/apps/typegpu-docs/src/components/translator/TranslatorApp.tsx +++ b/apps/typegpu-docs/src/components/translator/TranslatorApp.tsx @@ -19,7 +19,6 @@ import { wgslCodeAtom, } from './lib/translatorStore.ts'; import { useAutoCompile } from './lib/useAutoCompile.ts'; -import { main } from './lib/rolldown.ts'; interface EditorSectionProps { id: string; @@ -85,16 +84,6 @@ export default function TranslatorApp() { initialize(); }, [initialize]); - useEffect(() => { - (async () => { - const result = await main({ - 'index.ts': `console.log('Bruh')`, - }, ['index.ts']); - - console.log(result); - })(); - }, []); - const handleEditorLoaded = () => setEditorLoaded(false); const isTgslMode = mode === TRANSLATOR_MODES.TGSL; diff --git a/apps/typegpu-docs/src/components/translator/lib/rolldown.ts b/apps/typegpu-docs/src/components/translator/lib/rolldown.ts index b7f5fc481..a06ea21de 100644 --- a/apps/typegpu-docs/src/components/translator/lib/rolldown.ts +++ b/apps/typegpu-docs/src/components/translator/lib/rolldown.ts @@ -1,5 +1,5 @@ -import { resolve } from 'pathe'; import type { InputOptions, OutputOptions } from '@rolldown/browser'; +import { resolve } from 'pathe'; export interface BundleResult { output: Record; @@ -14,7 +14,7 @@ export interface SourceFile { export type FileMap = Record; -export async function main( +export async function bundle( files: FileMap, entries: string[], config: InputOptions & { output?: OutputOptions | undefined } = {}, @@ -39,14 +39,18 @@ export async function main( { name: 'virtual-fs', resolveId(source, importer) { - if (source[0] === '/' || source[0] === '.') { + if (source[0] === '/') { + // Absolute import + return source; + } + if (source[0] === '.') { + // Relative import return resolve(importer || '/', '..', source); } }, load(id) { if (id[0] !== '/') return; - const filename = id.slice(1); - return files[filename]; + return files[id]; }, }, ...(Array.isArray(config?.plugins) diff --git a/apps/typegpu-docs/src/components/translator/lib/tgslExecutor.ts b/apps/typegpu-docs/src/components/translator/lib/tgslExecutor.ts index 61e4f2ff8..f14e63af1 100644 --- a/apps/typegpu-docs/src/components/translator/lib/tgslExecutor.ts +++ b/apps/typegpu-docs/src/components/translator/lib/tgslExecutor.ts @@ -1,5 +1,6 @@ import * as Babel from '@babel/standalone'; import plugin from 'unplugin-typegpu/babel'; +import { bundle } from './rolldown.ts'; function translateTGSL( code: string, @@ -23,6 +24,18 @@ type TgslModule = Record; async function executeTgslModule(tgslCode: string): Promise { const translatedCode = translateTGSL(tgslCode); + const { output } = await bundle( + { + '/utils.ts': + 'export function add(a: number, b: number): number { return a + b; }', + '/index.ts': + `import {add} from './utils.ts'; console.log('Hello, World!');`, + }, + ['./index.ts'], + ); + + console.log(output); + const importMap = { imports: moduleImports }; const importMapScript = document.createElement('script'); diff --git a/apps/typegpu-docs/src/layouts/PageLayout.astro b/apps/typegpu-docs/src/layouts/PageLayout.astro index 395c14c0f..6da1112dd 100644 --- a/apps/typegpu-docs/src/layouts/PageLayout.astro +++ b/apps/typegpu-docs/src/layouts/PageLayout.astro @@ -1,76 +1,77 @@ --- -import '../fonts/font-face.css'; -import '../tailwind.css'; -import './loadingSpinner.css'; -const { title, theme = 'light' } = Astro.props; +import "../fonts/font-face.css"; +import "../tailwind.css"; +import "./loadingSpinner.css"; +const { title, theme = "light" } = Astro.props; --- - - {title ?? 'TypeGPU'} - - - - - - - - - + input[type="color"]::-webkit-color-swatch { + border: none; + } + + input[type="color"]::-moz-color-swatch { + border: none; + } + + + + + From 7fc452e2924c51cbae856c4cf170e784e942ffba Mon Sep 17 00:00:00 2001 From: Iwo Plaza Date: Mon, 18 Aug 2025 18:49:20 +0200 Subject: [PATCH 03/11] =?UTF-8?q?Working=20in=20dev,=20working=20in=20prod?= =?UTF-8?q?=20=F0=9F=8E=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/typegpu-docs/astro.config.mjs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/typegpu-docs/astro.config.mjs b/apps/typegpu-docs/astro.config.mjs index 21d140e3d..bd1ab6adb 100644 --- a/apps/typegpu-docs/astro.config.mjs +++ b/apps/typegpu-docs/astro.config.mjs @@ -25,6 +25,12 @@ const DEV = import.meta.env.DEV; export default defineConfig({ site: 'https://docs.swmansion.com', base: 'TypeGPU', + server: { + headers: { + 'Cross-Origin-Embedder-Policy': 'require-corp', + 'Cross-Origin-Opener-Policy': 'same-origin', + }, + }, vite: { define: { 'process.env.NODE_DEBUG_NATIVE': '""', @@ -32,11 +38,6 @@ export default defineConfig({ optimizeDeps: { exclude: ['@rolldown/browser'], }, - server: { - fs: { - allow: ['..'] - } - }, // Allowing query params, for invalidation plugins: [ wasm(), From 82797147e7437b72a4bb25d7bf7b8b95c0da488d Mon Sep 17 00:00:00 2001 From: Iwo Plaza Date: Mon, 18 Aug 2025 19:29:22 +0200 Subject: [PATCH 04/11] Create a browser variant of the rolldown plugin --- apps/typegpu-docs/public/coi-serviceworker.js | 1 - .../components/translator/lib/tgslExecutor.ts | 49 ++---- packages/unplugin-typegpu/package.json | 8 + packages/unplugin-typegpu/src/bun.ts | 2 +- packages/unplugin-typegpu/src/common.ts | 64 +++++++ packages/unplugin-typegpu/src/index.ts | 69 +------- .../unplugin-typegpu/src/rolldown-browser.ts | 153 ++++++++++++++++ pnpm-lock.yaml | 165 ++++++++++++++++++ 8 files changed, 413 insertions(+), 98 deletions(-) create mode 100644 packages/unplugin-typegpu/src/rolldown-browser.ts diff --git a/apps/typegpu-docs/public/coi-serviceworker.js b/apps/typegpu-docs/public/coi-serviceworker.js index 92b87f432..22091f9ff 100644 --- a/apps/typegpu-docs/public/coi-serviceworker.js +++ b/apps/typegpu-docs/public/coi-serviceworker.js @@ -35,7 +35,6 @@ if (typeof window === 'undefined') { self.addEventListener('fetch', (event) => { const r = event.request; - console.log('SERVICE: Intercepting request...', r); if (r.cache === 'only-if-cached' && r.mode !== 'same-origin') { return; } diff --git a/apps/typegpu-docs/src/components/translator/lib/tgslExecutor.ts b/apps/typegpu-docs/src/components/translator/lib/tgslExecutor.ts index f14e63af1..80993366d 100644 --- a/apps/typegpu-docs/src/components/translator/lib/tgslExecutor.ts +++ b/apps/typegpu-docs/src/components/translator/lib/tgslExecutor.ts @@ -1,18 +1,6 @@ -import * as Babel from '@babel/standalone'; -import plugin from 'unplugin-typegpu/babel'; +import rolldownPlugin from 'unplugin-typegpu/rolldown-browser'; import { bundle } from './rolldown.ts'; -function translateTGSL( - code: string, -): string { - const result = Babel.transform(code, { - 'presets': ['typescript'], - 'filename': 'example.ts', - plugins: [plugin], - }).code; - return result || ''; -} - const moduleImports = { 'typegpu': 'https://esm.sh/typegpu@latest/?bundle=false', 'typegpu/data': 'https://esm.sh/typegpu@latest/data/?bundle=false', @@ -22,19 +10,24 @@ const moduleImports = { type TgslModule = Record; async function executeTgslModule(tgslCode: string): Promise { - const translatedCode = translateTGSL(tgslCode); - - const { output } = await bundle( + const result = await bundle( { - '/utils.ts': - 'export function add(a: number, b: number): number { return a + b; }', - '/index.ts': - `import {add} from './utils.ts'; console.log('Hello, World!');`, + '/shader.js': tgslCode, + '/index.ts': ` + import tgpu from 'typegpu'; + import * as exports from './shader.js'; + + const shaderCode = tgpu.resolve({ externals: exports }); + export default shaderCode; + `, }, ['./index.ts'], + { + plugins: [rolldownPlugin({})], + }, ); - console.log(output); + const output = result.output['index.js']; const importMap = { imports: moduleImports }; @@ -44,7 +37,7 @@ async function executeTgslModule(tgslCode: string): Promise { document.head.appendChild(importMapScript); try { - const userBlob = new Blob([translatedCode], { type: 'text/javascript' }); + const userBlob = new Blob([output], { type: 'text/javascript' }); const userModuleUrl = URL.createObjectURL(userBlob); const module = await import(userModuleUrl); @@ -58,16 +51,8 @@ async function executeTgslModule(tgslCode: string): Promise { export async function executeTgslCode(tgslCode: string): Promise { try { - const exports = await executeTgslModule(tgslCode); - - const tgpuModule = await import( - //@ts-expect-error - 'https://esm.sh/typegpu@latest?bundle=false' - ); - - return tgpuModule.default.resolve({ - externals: exports as Record, - }); + const shaderCode = await executeTgslModule(tgslCode); + return shaderCode.default as string; } catch (error) { throw new Error( `Failed to execute TGSL code: ${ diff --git a/packages/unplugin-typegpu/package.json b/packages/unplugin-typegpu/package.json index decaa8a49..6421feee7 100644 --- a/packages/unplugin-typegpu/package.json +++ b/packages/unplugin-typegpu/package.json @@ -26,6 +26,7 @@ "./esbuild": "./src/esbuild.ts", "./farm": "./src/farm.ts", "./rolldown": "./src/rolldown.ts", + "./rolldown-browser": "./src/rolldown-browser.ts", "./rspack": "./src/rspack.ts", "./vite": "./src/vite.ts", "./webpack": "./src/webpack.ts" @@ -79,6 +80,12 @@ "import": "./dist/rolldown.js", "default": "./dist/rolldown.cjs" }, + "./rolldown-browser": { + "types": "./dist/rolldown-browser.d.ts", + "module": "./dist/rolldown-browser.js", + "import": "./dist/rolldown-browser.js", + "default": "./dist/rolldown-browser.cjs" + }, "./rspack": { "types": "./dist/rspack.d.ts", "module": "./dist/rspack.js", @@ -138,6 +145,7 @@ "@types/bun": "^1.2.19", "@types/picomatch": "^4.0.1", "acorn": "^8.14.1", + "rolldown": "1.0.0-beta.33", "rollup": "~4.37.0", "tsup": "catalog:build", "typescript": "catalog:types" diff --git a/packages/unplugin-typegpu/src/bun.ts b/packages/unplugin-typegpu/src/bun.ts index b7d9e1ebd..7080eafb0 100644 --- a/packages/unplugin-typegpu/src/bun.ts +++ b/packages/unplugin-typegpu/src/bun.ts @@ -17,7 +17,7 @@ export default (rawOptions: Options): BunPlugin => { } return { - name: 'TypeGPU', + name: 'unplugin-typegpu', setup(build) { build.onLoad({ filter: include }, async (args) => { const text = await Bun.file(args.path).text(); diff --git a/packages/unplugin-typegpu/src/common.ts b/packages/unplugin-typegpu/src/common.ts index da8dc6abb..643a7a49a 100644 --- a/packages/unplugin-typegpu/src/common.ts +++ b/packages/unplugin-typegpu/src/common.ts @@ -1,5 +1,6 @@ import type * as babel from '@babel/types'; import type * as acorn from 'acorn'; +import type { MagicStringAST } from 'magic-string-ast'; import type { FilterPattern } from 'unplugin'; export type Context = { @@ -243,6 +244,69 @@ export function performExpressionNaming( } } +export type FunctionNode = + | acorn.FunctionDeclaration + | acorn.AnonymousFunctionDeclaration + | acorn.FunctionExpression + | acorn.ArrowFunctionExpression; + +export function containsKernelDirective(node: FunctionNode): boolean { + if (node.body.type === 'BlockStatement') { + for (const statement of node.body.body) { + if ( + statement.type === 'ExpressionStatement' && + statement.directive === kernelDirective + ) { + return true; + } + } + } + return false; +} + +export function removeKernelDirective(node: FunctionNode) { + const cloned = structuredClone(node); + + if (cloned.body.type === 'BlockStatement') { + cloned.body.body = cloned.body.body.filter( + (statement) => + !( + statement.type === 'ExpressionStatement' && + statement.directive === kernelDirective + ), + ); + } + + return cloned; +} + +export function assignMetadata( + magicString: MagicStringAST, + node: acorn.AnyNode, + metadata: string, +) { + magicString.prependLeft( + node.start, + '(($ => (globalThis.__TYPEGPU_META__ ??= new WeakMap()).set($.f = (', + ).appendRight( + node.end, + `), ${metadata}) && $.f)({}))`, + ); +} + +export function wrapInAutoName( + magicString: MagicStringAST, + node: acorn.Node, + name: string, +) { + magicString + .prependLeft( + node.start, + '((globalThis.__TYPEGPU_AUTONAME__ ?? (a => a))(', + ) + .appendRight(node.end, `, "${name}"))`); +} + export const kernelDirective = 'kernel'; /** Regular expressions used for early pruning (to avoid unnecessary parsing, which is expensive) */ diff --git a/packages/unplugin-typegpu/src/index.ts b/packages/unplugin-typegpu/src/index.ts index 112672c91..33bf5410f 100644 --- a/packages/unplugin-typegpu/src/index.ts +++ b/packages/unplugin-typegpu/src/index.ts @@ -6,80 +6,21 @@ import { FORMAT_VERSION } from 'tinyest'; import { transpileFn } from 'tinyest-for-wgsl'; import { createUnplugin, type UnpluginInstance } from 'unplugin'; import { + assignMetadata, + containsKernelDirective, type Context, defaultOptions, earlyPruneRegex, embedJSON, + type FunctionNode, gatherTgpuAliases, isShellImplementationCall, - kernelDirective, type Options, performExpressionNaming, + removeKernelDirective, + wrapInAutoName, } from './common.ts'; -type FunctionNode = - | acorn.FunctionDeclaration - | acorn.AnonymousFunctionDeclaration - | acorn.FunctionExpression - | acorn.ArrowFunctionExpression; - -function containsKernelDirective(node: FunctionNode): boolean { - if (node.body.type === 'BlockStatement') { - for (const statement of node.body.body) { - if ( - statement.type === 'ExpressionStatement' && - statement.directive === kernelDirective - ) { - return true; - } - } - } - return false; -} - -function removeKernelDirective(node: FunctionNode) { - const cloned = structuredClone(node); - - if (cloned.body.type === 'BlockStatement') { - cloned.body.body = cloned.body.body.filter( - (statement) => - !( - statement.type === 'ExpressionStatement' && - statement.directive === kernelDirective - ), - ); - } - - return cloned; -} - -function assignMetadata( - magicString: MagicStringAST, - node: acorn.AnyNode, - metadata: string, -) { - magicString.prependLeft( - node.start, - '(($ => (globalThis.__TYPEGPU_META__ ??= new WeakMap()).set($.f = (', - ).appendRight( - node.end, - `), ${metadata}) && $.f)({}))`, - ); -} - -function wrapInAutoName( - magicString: MagicStringAST, - node: acorn.Node, - name: string, -) { - magicString - .prependLeft( - node.start, - '((globalThis.__TYPEGPU_AUTONAME__ ?? (a => a))(', - ) - .appendRight(node.end, `, "${name}"))`); -} - const typegpu: UnpluginInstance = createUnplugin( (rawOptions) => { const options = defu(rawOptions, defaultOptions); diff --git a/packages/unplugin-typegpu/src/rolldown-browser.ts b/packages/unplugin-typegpu/src/rolldown-browser.ts new file mode 100644 index 000000000..78abea6bd --- /dev/null +++ b/packages/unplugin-typegpu/src/rolldown-browser.ts @@ -0,0 +1,153 @@ +import type { Plugin } from 'rolldown'; +import type * as acorn from 'acorn'; +import { type Node, walk } from 'estree-walker'; +import { + assignMetadata, + containsKernelDirective, + type Context, + defaultOptions, + earlyPruneRegex, + embedJSON, + type FunctionNode, + gatherTgpuAliases, + isShellImplementationCall, + type Options, + performExpressionNaming, + removeKernelDirective, + wrapInAutoName, +} from './common.ts'; +import defu from 'defu'; +import { generateTransform, MagicStringAST } from 'magic-string-ast'; +import { FORMAT_VERSION } from 'tinyest'; +import { transpileFn } from 'tinyest-for-wgsl'; + +export default (rawOptions: Options): Plugin => { + const options = defu(rawOptions, defaultOptions); + return { + name: 'unplugin-typegpu' as const, + transform: { + filter: options.earlyPruning + ? { + id: options, + code: earlyPruneRegex, + } + : { + id: options, + }, + handler(code, id) { + const ctx: Context = { + tgpuAliases: new Set( + options.forceTgpuAlias ? [options.forceTgpuAlias] : [], + ), + fileId: id, + autoNamingEnabled: options.autoNamingEnabled, + }; + + let ast: Node; + try { + ast = this.parse(code, { + lang: 'ts', + }) as Node; + } catch (cause) { + console.warn( + `[unplugin-typegpu] Failed to parse ${id}. Cause: ${ + typeof cause === 'object' && cause && 'message' in cause + ? cause.message + : cause + }`, + ); + return undefined; + } + + const tgslFunctionDefs: { + def: FunctionNode; + name?: string | undefined; + }[] = []; + + const magicString = new MagicStringAST(code); + + walk(ast, { + enter(_node, _parent, prop, index) { + const node = _node as acorn.AnyNode; + + performExpressionNaming(ctx, node, (node, name) => { + wrapInAutoName(magicString, node, name); + }); + + if (node.type === 'ImportDeclaration') { + gatherTgpuAliases(node, ctx); + } + + if (node.type === 'CallExpression') { + if (isShellImplementationCall(node, ctx)) { + const implementation = node.arguments[0]; + + if ( + implementation && + (implementation.type === 'FunctionExpression' || + implementation.type === 'ArrowFunctionExpression') + ) { + tgslFunctionDefs.push({ + def: removeKernelDirective(implementation), + }); + this.skip(); + } + } + } + + if ( + node.type === 'ArrowFunctionExpression' || + node.type === 'FunctionExpression' || + node.type === 'FunctionDeclaration' + ) { + if (containsKernelDirective(node)) { + tgslFunctionDefs.push({ + def: removeKernelDirective(node), + name: node.type === 'FunctionDeclaration' || + node.type === 'FunctionExpression' + ? node.id?.name + : _parent?.type === 'VariableDeclarator' + ? _parent.id.type === 'Identifier' + ? _parent.id.name + : undefined + : undefined, + }); + this.skip(); + } + } + }, + }); + + for (const { def, name } of tgslFunctionDefs) { + const { params, body, externalNames } = transpileFn(def); + const isFunctionStatement = def.type === 'FunctionDeclaration'; + + if ( + isFunctionStatement && + name && + code.slice(0, def.start) + .search(new RegExp(`(?=6.9.0'} + '@oxc-project/runtime@0.82.2': + resolution: {integrity: sha512-cYxcj5CPn/vo5QSpCZcYzBiLidU5+GlFSqIeNaMgBDtcVRBsBJHZg3pHw999W6nHamFQ1EHuPPByB26tjaJiJw==} + engines: {node: '>=6.9.0'} + + '@oxc-project/types@0.82.2': + resolution: {integrity: sha512-WMGSwd9FsNBs/WfqIOH0h3k1LBdjZJQGYjGnC+vla/fh6HUsu5HzGPerRljiq1hgMQ6gs031YJR12VyP57b/hQ==} + '@pagefind/darwin-arm64@1.3.0': resolution: {integrity: sha512-365BEGl6ChOsauRjyVpBjXybflXAOvoMROw3TucAROHIcdBvXk9/2AmEvGFU0r75+vdQI4LJdJdpH4Y6Yqaj4A==} cpu: [arm64] @@ -2181,6 +2191,76 @@ packages: '@radix-ui/rect@1.1.1': resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} + '@rolldown/binding-android-arm64@1.0.0-beta.33': + resolution: {integrity: sha512-xhDQXKftRkEULIxCddrKMR8y0YO/Y+6BKk/XrQP2B29YjV2wr8DByoEz+AHX9BfLHb2srfpdN46UquBW2QXWpQ==} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.0-beta.33': + resolution: {integrity: sha512-7lhhY08v5ZtRq8JJQaJ49fnJombAPnqllKKCDLU/UvaqNAOEyTGC8J1WVOLC4EA4zbXO5U3CCRgVGyAFNH2VtQ==} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.0-beta.33': + resolution: {integrity: sha512-U2iGjcDV7NWyYyhap8YuY0nwrLX6TvX/9i7gBtdEMPm9z3wIUVGNMVdGlA43uqg7xDpRGpEqGnxbeDgiEwYdnA==} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.0-beta.33': + resolution: {integrity: sha512-gd6ASromVHFLlzrjJWMG5CXHkS7/36DEZ8HhvGt2NN8eZALCIuyEx8HMMLqvKA7z4EAztVkdToVrdxpGMsKZxw==} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.33': + resolution: {integrity: sha512-xmeLfkfGthuynO1EpCdyTVr0r4G+wqvnKCuyR6rXOet+hLrq5HNAC2XtP/jU2TB4Bc6aiLYxl868B8CGtFDhcw==} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.33': + resolution: {integrity: sha512-cHGp8yfHL4pes6uaLbO5L58ceFkUK4efd8iE86jClD1QPPDLKiqEXJCFYeuK3OfODuF5EBOmf0SlcUZNEYGdmw==} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-arm64-musl@1.0.0-beta.33': + resolution: {integrity: sha512-wZ1t7JAvVeFgskH1L9y7c47ITitPytpL0s8FmAT8pVfXcaTmS58ZyoXT+y6cz8uCkQnETjrX3YezTGI18u3ecg==} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-x64-gnu@1.0.0-beta.33': + resolution: {integrity: sha512-cDndWo3VEYbm7yeujOV6Ie2XHz0K8YX/R/vbNmMo03m1QwtBKKvbYNSyJb3B9+8igltDjd8zNM9mpiNNrq/ekQ==} + cpu: [x64] + os: [linux] + + '@rolldown/binding-linux-x64-musl@1.0.0-beta.33': + resolution: {integrity: sha512-bl7uzi6es/l6LT++NZcBpiX43ldLyKXCPwEZGY1rZJ99HQ7m1g3KxWwYCcGxtKjlb2ExVvDZicF6k+96vxOJKg==} + cpu: [x64] + os: [linux] + + '@rolldown/binding-openharmony-arm64@1.0.0-beta.33': + resolution: {integrity: sha512-TrgzQanpLgcmmzolCbYA9BPZgF1gYxkIGZhU/HROnJPsq67gcyaYw/JBLioqQLjIwMipETkn25YY799D2OZzJA==} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.0-beta.33': + resolution: {integrity: sha512-z0LltdUfvoKak9SuaLz/M9AVSg+RTOZjFksbZXzC6Svl1odyW4ai21VHhZy3m2Faeeb/rl/9efVLayj+qYEGxw==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.33': + resolution: {integrity: sha512-CpvOHyqDNOYx9riD4giyXQDIu72bWRU2Dwt1xFSPlBudk6NumK0OJl6Ch+LPnkp5podQHcQg0mMauAXPVKct7g==} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.33': + resolution: {integrity: sha512-/tNTvZTWHz6HiVuwpR3zR0kGIyCNb+/tFhnJmti+Aw2fAXs3l7Aj0DcXd0646eFKMX8L2w5hOW9H08FXTUkN0g==} + cpu: [ia32] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.0-beta.33': + resolution: {integrity: sha512-Bb2qK3z7g2mf4zaKRvkohHzweaP1lLbaoBmXZFkY6jJWMm0Z8Pfnh8cOoRlH1IVM1Ufbo8ZZ1WXp1LbOpRMtXw==} + cpu: [x64] + os: [win32] + '@rolldown/browser@1.0.0-beta.32': resolution: {integrity: sha512-g9Cj/Kn3gO//7eT9RRLN7Zb6juFqSJJjVfm3Mv1aivZW5a66VSEXuQnkCHPsTST4qVnrRXnyGjUk5ftVTKk80A==} hasBin: true @@ -2188,6 +2268,9 @@ packages: '@rolldown/pluginutils@1.0.0-beta.19': resolution: {integrity: sha512-3FL3mnMbPu0muGOCaKAhhFEYmqv9eTfPSJRJmANrCwtgK8VuxpsZDGK+m0LYAGoyO8+0j5uRe4PeyPDK1yA/hA==} + '@rolldown/pluginutils@1.0.0-beta.33': + resolution: {integrity: sha512-she25NCG6NoEPC/SEB4pHs5STcnfI4VBFOzjeI63maSPrWME5J2XC8ogrBgp8NaE/xzj28/kbpSaebiMvFRj+w==} + '@rollup/plugin-alias@5.1.1': resolution: {integrity: sha512-PR9zDb+rOzkRb2VD+EuKB7UC41vU5DIwZ5qqCpk0KJudcWAyi8rvYOhS7+L5aZCspw1stTViLgN5v6FF1p5cgQ==} engines: {node: '>=14.0.0'} @@ -2775,6 +2858,10 @@ packages: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} + ansis@4.1.0: + resolution: {integrity: sha512-BGcItUBWSMRgOCe+SVZJ+S7yTRG0eGt9cXAHev72yuGcY23hnLA7Bky5L/xLyPINoSN95geovfBkqoTlNZYa7w==} + engines: {node: '>=14'} + any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} @@ -5109,6 +5196,10 @@ packages: robust-predicates@3.0.2: resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} + rolldown@1.0.0-beta.33: + resolution: {integrity: sha512-mgu118ZuRguC8unhPCbdZbyRbjQfEMiWqlojBA5aRIncBelRaBomnHNpGKYkYWeK7twRz5Cql30xgqqrA3Xelw==} + hasBin: true + rollup-plugin-dts@6.1.1: resolution: {integrity: sha512-aSHRcJ6KG2IHIioYlvAOcEq6U99sVtqDDKVhnwt70rW6tsz3tv5OSjEiWcgzfsHdLyGXZ/3b/7b/+Za3Y6r1XA==} engines: {node: '>=16'} @@ -7332,6 +7423,10 @@ snapshots: '@oxc-project/runtime@0.81.0': {} + '@oxc-project/runtime@0.82.2': {} + + '@oxc-project/types@0.82.2': {} + '@pagefind/darwin-arm64@1.3.0': optional: true @@ -7604,6 +7699,50 @@ snapshots: '@radix-ui/rect@1.1.1': {} + '@rolldown/binding-android-arm64@1.0.0-beta.33': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.0-beta.33': + optional: true + + '@rolldown/binding-darwin-x64@1.0.0-beta.33': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.0-beta.33': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.33': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.33': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.0-beta.33': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.0-beta.33': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.0-beta.33': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.0-beta.33': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.0-beta.33': + dependencies: + '@napi-rs/wasm-runtime': 1.0.3 + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.33': + optional: true + + '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.33': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.0-beta.33': + optional: true + '@rolldown/browser@1.0.0-beta.32': dependencies: '@napi-rs/wasm-runtime': 1.0.3 @@ -7611,6 +7750,8 @@ snapshots: '@rolldown/pluginutils@1.0.0-beta.19': {} + '@rolldown/pluginutils@1.0.0-beta.33': {} + '@rollup/plugin-alias@5.1.1(rollup@4.34.8)': optionalDependencies: rollup: 4.34.8 @@ -8209,6 +8350,8 @@ snapshots: ansi-styles@6.2.1: {} + ansis@4.1.0: {} + any-promise@1.3.0: {} anymatch@3.1.3: @@ -11121,6 +11264,28 @@ snapshots: robust-predicates@3.0.2: {} + rolldown@1.0.0-beta.33: + dependencies: + '@oxc-project/runtime': 0.82.2 + '@oxc-project/types': 0.82.2 + '@rolldown/pluginutils': 1.0.0-beta.33 + ansis: 4.1.0 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.0-beta.33 + '@rolldown/binding-darwin-arm64': 1.0.0-beta.33 + '@rolldown/binding-darwin-x64': 1.0.0-beta.33 + '@rolldown/binding-freebsd-x64': 1.0.0-beta.33 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.33 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.33 + '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.33 + '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.33 + '@rolldown/binding-linux-x64-musl': 1.0.0-beta.33 + '@rolldown/binding-openharmony-arm64': 1.0.0-beta.33 + '@rolldown/binding-wasm32-wasi': 1.0.0-beta.33 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.33 + '@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.33 + '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.33 + rollup-plugin-dts@6.1.1(rollup@4.34.8)(typescript@5.8.3): dependencies: magic-string: 0.30.17 From ff570bd817c2d8d34edbc4d2983001fd3811229d Mon Sep 17 00:00:00 2001 From: Iwo Plaza Date: Tue, 19 Aug 2025 16:01:24 +0200 Subject: [PATCH 05/11] Use typegpu from source --- .../src/components/CodeEditor.tsx | 2 +- .../components/translator/lib/editorConfig.ts | 2 +- .../src/components/translator/lib/rolldown.ts | 41 ++++++++++---- .../components/translator/lib/tgslExecutor.ts | 26 +++++---- .../src/utils/examples/sandboxModules.ts | 53 ++++++++++++++++--- 5 files changed, 93 insertions(+), 31 deletions(-) diff --git a/apps/typegpu-docs/src/components/CodeEditor.tsx b/apps/typegpu-docs/src/components/CodeEditor.tsx index a086536cb..aadbc2531 100644 --- a/apps/typegpu-docs/src/components/CodeEditor.tsx +++ b/apps/typegpu-docs/src/components/CodeEditor.tsx @@ -17,7 +17,7 @@ function handleEditorWillMount(monaco: Monaco) { entries(SANDBOX_MODULES), map(([key, moduleDef]) => { if ('reroute' in moduleDef.typeDef) { - return [key, moduleDef.typeDef.reroute] as const; + return [key, [moduleDef.typeDef.reroute]] as [string, string[]]; } return null; }), diff --git a/apps/typegpu-docs/src/components/translator/lib/editorConfig.ts b/apps/typegpu-docs/src/components/translator/lib/editorConfig.ts index 10450ad6b..90a8c5464 100644 --- a/apps/typegpu-docs/src/components/translator/lib/editorConfig.ts +++ b/apps/typegpu-docs/src/components/translator/lib/editorConfig.ts @@ -44,7 +44,7 @@ export function setupMonacoEditor(monaco: Monaco) { entries(SANDBOX_MODULES), map(([key, moduleDef]) => { if ('reroute' in moduleDef.typeDef) { - return [key, moduleDef.typeDef.reroute] as const; + return [key, [moduleDef.typeDef.reroute]] as [string, string[]]; } return null; }), diff --git a/apps/typegpu-docs/src/components/translator/lib/rolldown.ts b/apps/typegpu-docs/src/components/translator/lib/rolldown.ts index a06ea21de..b2e6b8684 100644 --- a/apps/typegpu-docs/src/components/translator/lib/rolldown.ts +++ b/apps/typegpu-docs/src/components/translator/lib/rolldown.ts @@ -1,5 +1,5 @@ import type { InputOptions, OutputOptions } from '@rolldown/browser'; -import { resolve } from 'pathe'; +import { join } from 'pathe'; export interface BundleResult { output: Record; @@ -12,7 +12,14 @@ export interface SourceFile { isEntry?: boolean; } -export type FileMap = Record; +export type FileMap = Record< + string, + { + content: string; + } | { + reroute: string; + } | undefined +>; export async function bundle( files: FileMap, @@ -39,18 +46,32 @@ export async function bundle( { name: 'virtual-fs', resolveId(source, importer) { - if (source[0] === '/') { - // Absolute import - return source; + if (source.includes('typegpu') || importer?.includes('typegpu')) { + debug = true; } - if (source[0] === '.') { - // Relative import - return resolve(importer || '/', '..', source); + + const id = source[0] === '.' + ? join(importer || '/', '..', source) + : source; + + if (files[id] && 'reroute' in files[id]) { + // Rerouting + return files[id].reroute; } + + return id; }, load(id) { - if (id[0] !== '/') return; - return files[id]; + if (!files[id]) { + return; + } + + if ('reroute' in files[id]) { + // Reroutes are supposed to be resolved in `resolveId` + throw new Error(`Unresolved reroute for ${id}`); + } + + return files[id].content; }, }, ...(Array.isArray(config?.plugins) diff --git a/apps/typegpu-docs/src/components/translator/lib/tgslExecutor.ts b/apps/typegpu-docs/src/components/translator/lib/tgslExecutor.ts index 80993366d..fe2da298e 100644 --- a/apps/typegpu-docs/src/components/translator/lib/tgslExecutor.ts +++ b/apps/typegpu-docs/src/components/translator/lib/tgslExecutor.ts @@ -1,10 +1,10 @@ +import { mapValues, pipe } from 'remeda'; import rolldownPlugin from 'unplugin-typegpu/rolldown-browser'; import { bundle } from './rolldown.ts'; +import { SANDBOX_MODULES } from '../../../utils/examples/sandboxModules.ts'; const moduleImports = { - 'typegpu': 'https://esm.sh/typegpu@latest/?bundle=false', - 'typegpu/data': 'https://esm.sh/typegpu@latest/data/?bundle=false', - 'typegpu/std': 'https://esm.sh/typegpu@latest/std/?bundle=false', + 'typed-binary': 'https://esm.sh/typed-binary@latest', } as Record; type TgslModule = Record; @@ -12,18 +12,22 @@ type TgslModule = Record; async function executeTgslModule(tgslCode: string): Promise { const result = await bundle( { - '/shader.js': tgslCode, - '/index.ts': ` - import tgpu from 'typegpu'; - import * as exports from './shader.js'; + ...pipe(SANDBOX_MODULES, mapValues((val) => val.import)), + '/shader.js': { content: tgslCode }, + '/index.ts': { + content: ` + import tgpu from 'typegpu'; + import * as exports from './shader.js'; - const shaderCode = tgpu.resolve({ externals: exports }); - export default shaderCode; - `, + const shaderCode = tgpu.resolve({ externals: exports }); + export default shaderCode; + `, + }, }, ['./index.ts'], { plugins: [rolldownPlugin({})], + external: ['typed-binary'], }, ); @@ -40,7 +44,7 @@ async function executeTgslModule(tgslCode: string): Promise { const userBlob = new Blob([output], { type: 'text/javascript' }); const userModuleUrl = URL.createObjectURL(userBlob); - const module = await import(userModuleUrl); + const module = await import(/* @vite-ignore */ userModuleUrl); URL.revokeObjectURL(userModuleUrl); return module; diff --git a/apps/typegpu-docs/src/utils/examples/sandboxModules.ts b/apps/typegpu-docs/src/utils/examples/sandboxModules.ts index 350e809dd..8d5b31987 100644 --- a/apps/typegpu-docs/src/utils/examples/sandboxModules.ts +++ b/apps/typegpu-docs/src/utils/examples/sandboxModules.ts @@ -4,7 +4,32 @@ import dtsWebGPU from '@webgpu/types/dist/index.d.ts?raw'; import dtsWgpuMatrix from 'wgpu-matrix/dist/3.x/wgpu-matrix.d.ts?raw'; interface SandboxModuleDefinition { - typeDef: { filename?: string; content: string } | { reroute: string[] }; + typeDef: + | { filename?: string; content: string } + | { reroute: string }; + import?: + | { filename?: string; content: string } + | { reroute: string } + | undefined; +} + +function srcFileToModule( + [filepath, content]: [string, string], + baseUrl: string, +): [moduleKey: string, moduleDef: SandboxModuleDefinition] { + const filename = filepath.replace(baseUrl, ''); + const def = { + filename, + content, + }; + + return [ + filename, + { + typeDef: def, + import: def, + }, + ] as const; } function dtsFileToModule( @@ -26,13 +51,16 @@ function dtsFileToModule( const allPackagesSrcFiles = pipe( entries( - import.meta.glob('../../../../../packages/*/src/**/*.ts', { + import.meta.glob([ + '../../../../../packages/*/src/**/*.ts', + '../../../../../packages/*/package.json', + ], { query: 'raw', eager: true, import: 'default', }) as Record, ), - map((dtsFile) => dtsFileToModule(dtsFile, '../../../../../packages/')), + map((dtsFile) => srcFileToModule(dtsFile, '../../../../../packages/')), fromEntries(), ); @@ -61,21 +89,30 @@ export const SANDBOX_MODULES: Record = { 'wgpu-matrix': { typeDef: { filename: 'wgpu-matrix.d.ts', content: dtsWgpuMatrix }, }, + tinyest: { + import: { reroute: 'tinyest/src/index.ts' }, + typeDef: { reroute: 'tinyest/src/index.ts' }, + }, typegpu: { - typeDef: { reroute: ['typegpu/src/index.ts'] }, + import: { reroute: 'typegpu/src/index.ts' }, + typeDef: { reroute: 'typegpu/src/index.ts' }, }, 'typegpu/data': { - typeDef: { reroute: ['typegpu/src/data/index.ts'] }, + import: { reroute: 'typegpu/src/data/index.ts' }, + typeDef: { reroute: 'typegpu/src/data/index.ts' }, }, 'typegpu/std': { - typeDef: { reroute: ['typegpu/src/std/index.ts'] }, + import: { reroute: 'typegpu/src/std/index.ts' }, + typeDef: { reroute: 'typegpu/src/std/index.ts' }, }, // Utility modules '@typegpu/noise': { - typeDef: { reroute: ['typegpu-noise/src/index.ts'] }, + import: { reroute: 'typegpu-noise/src/index.ts' }, + typeDef: { reroute: 'typegpu-noise/src/index.ts' }, }, '@typegpu/color': { - typeDef: { reroute: ['typegpu-color/src/index.ts'] }, + import: { reroute: 'typegpu-color/src/index.ts' }, + typeDef: { reroute: 'typegpu-color/src/index.ts' }, }, }; From b7bc9537d3f56943ce0d598f6f03ef4b30777c61 Mon Sep 17 00:00:00 2001 From: Iwo Plaza Date: Tue, 19 Aug 2025 17:31:49 +0200 Subject: [PATCH 06/11] Cleanup --- .../src/components/translator/lib/constants.ts | 12 +++--------- .../src/components/translator/lib/rolldown.ts | 4 ---- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/apps/typegpu-docs/src/components/translator/lib/constants.ts b/apps/typegpu-docs/src/components/translator/lib/constants.ts index 313bd47a1..de5e2b5da 100644 --- a/apps/typegpu-docs/src/components/translator/lib/constants.ts +++ b/apps/typegpu-docs/src/components/translator/lib/constants.ts @@ -23,7 +23,6 @@ fn fs_main() -> @location(0) vec4 { export const DEFAULT_TGSL = `import tgpu from 'typegpu'; import * as d from 'typegpu/data'; -import * as std from 'typegpu/std'; const Particle = d.struct({ position: d.vec3f, @@ -42,14 +41,9 @@ const layout = tgpu.bindGroupLayout({ export const updateParicle = tgpu.fn([Particle, d.vec3f, d.f32], Particle)( (particle, gravity, deltaTime) => { - const newVelocity = std.mul( - particle.velocity, - std.mul(gravity, deltaTime), - ); - const newPosition = std.add( - particle.position, - std.mul(newVelocity, deltaTime), - ); + const newVelocity = particle.velocity.mul(gravity).mul(deltaTime); + const newPosition = particle.position.add(newVelocity.mul(deltaTime)); + return Particle({ position: newPosition, velocity: newVelocity, diff --git a/apps/typegpu-docs/src/components/translator/lib/rolldown.ts b/apps/typegpu-docs/src/components/translator/lib/rolldown.ts index b2e6b8684..cd8114184 100644 --- a/apps/typegpu-docs/src/components/translator/lib/rolldown.ts +++ b/apps/typegpu-docs/src/components/translator/lib/rolldown.ts @@ -46,10 +46,6 @@ export async function bundle( { name: 'virtual-fs', resolveId(source, importer) { - if (source.includes('typegpu') || importer?.includes('typegpu')) { - debug = true; - } - const id = source[0] === '.' ? join(importer || '/', '..', source) : source; From d416fdabbb81fa36361448a01d8132373af6ffbc Mon Sep 17 00:00:00 2001 From: Iwo Plaza Date: Tue, 19 Aug 2025 17:44:26 +0200 Subject: [PATCH 07/11] Cleanup and formatting fixes --- apps/typegpu-docs/astro.config.mjs | 4 + .../components/translator/lib/tgslExecutor.ts | 9 +- .../typegpu-docs/src/layouts/PageLayout.astro | 122 +++++++++--------- 3 files changed, 69 insertions(+), 66 deletions(-) diff --git a/apps/typegpu-docs/astro.config.mjs b/apps/typegpu-docs/astro.config.mjs index bd1ab6adb..e06291bad 100644 --- a/apps/typegpu-docs/astro.config.mjs +++ b/apps/typegpu-docs/astro.config.mjs @@ -26,6 +26,9 @@ export default defineConfig({ site: 'https://docs.swmansion.com', base: 'TypeGPU', server: { + // Required for '@rolldown/browser' to work in dev mode. + // Since the service worker is hosted on the /TypeGPU path, + // fetches from /@fs/ fail due to CORS. This fixes that. headers: { 'Cross-Origin-Embedder-Policy': 'require-corp', 'Cross-Origin-Opener-Policy': 'same-origin', @@ -33,6 +36,7 @@ export default defineConfig({ }, vite: { define: { + // Required for '@rolldown/browser' to work. 'process.env.NODE_DEBUG_NATIVE': '""', }, optimizeDeps: { diff --git a/apps/typegpu-docs/src/components/translator/lib/tgslExecutor.ts b/apps/typegpu-docs/src/components/translator/lib/tgslExecutor.ts index fe2da298e..c09965984 100644 --- a/apps/typegpu-docs/src/components/translator/lib/tgslExecutor.ts +++ b/apps/typegpu-docs/src/components/translator/lib/tgslExecutor.ts @@ -13,11 +13,11 @@ async function executeTgslModule(tgslCode: string): Promise { const result = await bundle( { ...pipe(SANDBOX_MODULES, mapValues((val) => val.import)), - '/shader.js': { content: tgslCode }, + '/shader.ts': { content: tgslCode }, '/index.ts': { content: ` import tgpu from 'typegpu'; - import * as exports from './shader.js'; + import * as exports from './shader.ts'; const shaderCode = tgpu.resolve({ externals: exports }); export default shaderCode; @@ -31,17 +31,16 @@ async function executeTgslModule(tgslCode: string): Promise { }, ); - const output = result.output['index.js']; + const translatedCode = result.output['index.js']; const importMap = { imports: moduleImports }; - const importMapScript = document.createElement('script'); importMapScript.type = 'importmap'; importMapScript.textContent = JSON.stringify(importMap); document.head.appendChild(importMapScript); try { - const userBlob = new Blob([output], { type: 'text/javascript' }); + const userBlob = new Blob([translatedCode], { type: 'text/javascript' }); const userModuleUrl = URL.createObjectURL(userBlob); const module = await import(/* @vite-ignore */ userModuleUrl); diff --git a/apps/typegpu-docs/src/layouts/PageLayout.astro b/apps/typegpu-docs/src/layouts/PageLayout.astro index 6da1112dd..9d3db9309 100644 --- a/apps/typegpu-docs/src/layouts/PageLayout.astro +++ b/apps/typegpu-docs/src/layouts/PageLayout.astro @@ -1,77 +1,77 @@ --- -import "../fonts/font-face.css"; -import "../tailwind.css"; -import "./loadingSpinner.css"; -const { title, theme = "light" } = Astro.props; +import '../fonts/font-face.css'; +import '../tailwind.css'; +import './loadingSpinner.css'; +const { title, theme = 'light' } = Astro.props; --- - - {title ?? "TypeGPU"} - - - - - - - - - - + input[type="color"]::-moz-color-swatch { + border: none; + } + + + + + From 9ff9e55919726152c4550fc5939565d8cdfdd92a Mon Sep 17 00:00:00 2001 From: Iwo Plaza Date: Tue, 19 Aug 2025 17:46:30 +0200 Subject: [PATCH 08/11] Really fix formatting --- apps/typegpu-docs/src/layouts/PageLayout.astro | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/typegpu-docs/src/layouts/PageLayout.astro b/apps/typegpu-docs/src/layouts/PageLayout.astro index 9d3db9309..9ba9b4542 100644 --- a/apps/typegpu-docs/src/layouts/PageLayout.astro +++ b/apps/typegpu-docs/src/layouts/PageLayout.astro @@ -7,7 +7,7 @@ const { title, theme = 'light' } = Astro.props; - {title ?? "TypeGPU"} + {title ?? 'TypeGPU'} @@ -29,7 +29,7 @@ const { title, theme = 'light' } = Astro.props; @reference "../tailwind.css"; @layer base { h1 { - @apply m-0 lg:text-[3.25rem] md:text-[2.5rem] text-[1.4375rem] leading-[130%]; + @apply m-0 lg:text-[3.25rem] md:text-[2.5rem] text-[1.4375rem] leading-[130%]; } h2 { @@ -53,20 +53,20 @@ const { title, theme = 'light' } = Astro.props; margin: 0; } - [data-theme="dark"] body { + [data-theme='dark'] body { background-color: #171724; color: white; } - [data-theme="light"] body { + [data-theme='light'] body { background-color: white; } - input[type="color"]::-webkit-color-swatch { + input[type='color']::-webkit-color-swatch { border: none; } - input[type="color"]::-moz-color-swatch { + input[type='color']::-moz-color-swatch { border: none; } From cce0ec84890981ee8277e9f578a4042aa611371f Mon Sep 17 00:00:00 2001 From: Iwo Plaza Date: Tue, 19 Aug 2025 18:38:18 +0200 Subject: [PATCH 09/11] Reuse logic for the rolldown browser plugin variant --- packages/unplugin-typegpu/src/index.ts | 26 ++- .../unplugin-typegpu/src/rolldown-browser.ts | 154 +----------------- 2 files changed, 26 insertions(+), 154 deletions(-) diff --git a/packages/unplugin-typegpu/src/index.ts b/packages/unplugin-typegpu/src/index.ts index 33bf5410f..df10caad3 100644 --- a/packages/unplugin-typegpu/src/index.ts +++ b/packages/unplugin-typegpu/src/index.ts @@ -4,7 +4,11 @@ import { type Node, walk } from 'estree-walker'; import { generateTransform, MagicStringAST } from 'magic-string-ast'; import { FORMAT_VERSION } from 'tinyest'; import { transpileFn } from 'tinyest-for-wgsl'; -import { createUnplugin, type UnpluginInstance } from 'unplugin'; +import { + createUnplugin, + type UnpluginFactory, + type UnpluginInstance, +} from 'unplugin'; import { assignMetadata, containsKernelDirective, @@ -21,7 +25,24 @@ import { wrapInAutoName, } from './common.ts'; -const typegpu: UnpluginInstance = createUnplugin( +export const createUberPlugin = ( + factory: UnpluginFactory, +): UnpluginInstance => { + const standardPlugins = createUnplugin(factory); + + return { + ...standardPlugins, + rolldownBrowser: ((options: Options) => { + // The unplugin API is based on the rollup/rolldonw APIs, so it + // should just be a compatible rolldown plugin. + return factory(options, { + framework: 'rolldown', + }); + }), + }; +}; + +const typegpu = createUberPlugin( (rawOptions) => { const options = defu(rawOptions, defaultOptions); @@ -164,6 +185,7 @@ export default typegpu; export const vitePlugin = typegpu.vite; export const rollupPlugin = typegpu.rollup; export const rolldownPlugin = typegpu.rolldown; +export const rolldownBrowserPlugin = typegpu.rolldownBrowser; export const webpackPlugin = typegpu.webpack; export const rspackPlugin = typegpu.rspack; export const esbuildPlugin = typegpu.esbuild; diff --git a/packages/unplugin-typegpu/src/rolldown-browser.ts b/packages/unplugin-typegpu/src/rolldown-browser.ts index 78abea6bd..2c0fbe185 100644 --- a/packages/unplugin-typegpu/src/rolldown-browser.ts +++ b/packages/unplugin-typegpu/src/rolldown-browser.ts @@ -1,153 +1,3 @@ -import type { Plugin } from 'rolldown'; -import type * as acorn from 'acorn'; -import { type Node, walk } from 'estree-walker'; -import { - assignMetadata, - containsKernelDirective, - type Context, - defaultOptions, - earlyPruneRegex, - embedJSON, - type FunctionNode, - gatherTgpuAliases, - isShellImplementationCall, - type Options, - performExpressionNaming, - removeKernelDirective, - wrapInAutoName, -} from './common.ts'; -import defu from 'defu'; -import { generateTransform, MagicStringAST } from 'magic-string-ast'; -import { FORMAT_VERSION } from 'tinyest'; -import { transpileFn } from 'tinyest-for-wgsl'; +import { rolldownBrowserPlugin } from './index.ts'; -export default (rawOptions: Options): Plugin => { - const options = defu(rawOptions, defaultOptions); - return { - name: 'unplugin-typegpu' as const, - transform: { - filter: options.earlyPruning - ? { - id: options, - code: earlyPruneRegex, - } - : { - id: options, - }, - handler(code, id) { - const ctx: Context = { - tgpuAliases: new Set( - options.forceTgpuAlias ? [options.forceTgpuAlias] : [], - ), - fileId: id, - autoNamingEnabled: options.autoNamingEnabled, - }; - - let ast: Node; - try { - ast = this.parse(code, { - lang: 'ts', - }) as Node; - } catch (cause) { - console.warn( - `[unplugin-typegpu] Failed to parse ${id}. Cause: ${ - typeof cause === 'object' && cause && 'message' in cause - ? cause.message - : cause - }`, - ); - return undefined; - } - - const tgslFunctionDefs: { - def: FunctionNode; - name?: string | undefined; - }[] = []; - - const magicString = new MagicStringAST(code); - - walk(ast, { - enter(_node, _parent, prop, index) { - const node = _node as acorn.AnyNode; - - performExpressionNaming(ctx, node, (node, name) => { - wrapInAutoName(magicString, node, name); - }); - - if (node.type === 'ImportDeclaration') { - gatherTgpuAliases(node, ctx); - } - - if (node.type === 'CallExpression') { - if (isShellImplementationCall(node, ctx)) { - const implementation = node.arguments[0]; - - if ( - implementation && - (implementation.type === 'FunctionExpression' || - implementation.type === 'ArrowFunctionExpression') - ) { - tgslFunctionDefs.push({ - def: removeKernelDirective(implementation), - }); - this.skip(); - } - } - } - - if ( - node.type === 'ArrowFunctionExpression' || - node.type === 'FunctionExpression' || - node.type === 'FunctionDeclaration' - ) { - if (containsKernelDirective(node)) { - tgslFunctionDefs.push({ - def: removeKernelDirective(node), - name: node.type === 'FunctionDeclaration' || - node.type === 'FunctionExpression' - ? node.id?.name - : _parent?.type === 'VariableDeclarator' - ? _parent.id.type === 'Identifier' - ? _parent.id.name - : undefined - : undefined, - }); - this.skip(); - } - } - }, - }); - - for (const { def, name } of tgslFunctionDefs) { - const { params, body, externalNames } = transpileFn(def); - const isFunctionStatement = def.type === 'FunctionDeclaration'; - - if ( - isFunctionStatement && - name && - code.slice(0, def.start) - .search(new RegExp(`(? Date: Wed, 3 Sep 2025 20:32:35 +0200 Subject: [PATCH 10/11] Fix type issue --- packages/unplugin-typegpu/src/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/unplugin-typegpu/src/index.ts b/packages/unplugin-typegpu/src/index.ts index df10caad3..93afed9d2 100644 --- a/packages/unplugin-typegpu/src/index.ts +++ b/packages/unplugin-typegpu/src/index.ts @@ -27,11 +27,11 @@ import { export const createUberPlugin = ( factory: UnpluginFactory, -): UnpluginInstance => { +) => { const standardPlugins = createUnplugin(factory); return { - ...standardPlugins, + ...standardPlugins as UnpluginInstance, rolldownBrowser: ((options: Options) => { // The unplugin API is based on the rollup/rolldonw APIs, so it // should just be a compatible rolldown plugin. From 62914b060f4925bb0b890ffd7372e541b36764c6 Mon Sep 17 00:00:00 2001 From: Iwo Plaza Date: Wed, 3 Sep 2025 20:34:18 +0200 Subject: [PATCH 11/11] Update lock file --- pnpm-lock.yaml | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 16dd08053..1e9eba3d8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -972,8 +972,8 @@ packages: '@emmetio/stream-reader@2.2.0': resolution: {integrity: sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw==} - '@emnapi/core@1.4.5': - resolution: {integrity: sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q==} + '@emnapi/core@1.5.0': + resolution: {integrity: sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==} '@emnapi/runtime@1.4.3': resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==} @@ -981,11 +981,11 @@ packages: '@emnapi/runtime@1.4.4': resolution: {integrity: sha512-hHyapA4A3gPaDCNfiqyZUStTMqIkKRshqPIuDOXv1hcBnD4U3l8cP0T1HMCfGRxQ6V64TGCcoswChANyOAwbQg==} - '@emnapi/runtime@1.4.5': - resolution: {integrity: sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==} + '@emnapi/runtime@1.5.0': + resolution: {integrity: sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==} - '@emnapi/wasi-threads@1.0.4': - resolution: {integrity: sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g==} + '@emnapi/wasi-threads@1.1.0': + resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} '@esbuild/aix-ppc64@0.24.2': resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==} @@ -6925,9 +6925,9 @@ snapshots: '@emmetio/stream-reader@2.2.0': {} - '@emnapi/core@1.4.5': + '@emnapi/core@1.5.0': dependencies: - '@emnapi/wasi-threads': 1.0.4 + '@emnapi/wasi-threads': 1.1.0 tslib: 2.8.1 '@emnapi/runtime@1.4.3': @@ -6940,11 +6940,11 @@ snapshots: tslib: 2.8.1 optional: true - '@emnapi/runtime@1.4.5': + '@emnapi/runtime@1.5.0': dependencies: tslib: 2.8.1 - '@emnapi/wasi-threads@1.0.4': + '@emnapi/wasi-threads@1.1.0': dependencies: tslib: 2.8.1 @@ -7550,8 +7550,8 @@ snapshots: '@napi-rs/wasm-runtime@1.0.3': dependencies: - '@emnapi/core': 1.4.5 - '@emnapi/runtime': 1.4.5 + '@emnapi/core': 1.5.0 + '@emnapi/runtime': 1.5.0 '@tybys/wasm-util': 0.10.0 '@nodelib/fs.scandir@2.1.5': @@ -8849,11 +8849,6 @@ snapshots: '@types/node': 24.3.0 '@types/react': 19.1.8 - bun-types@1.2.20(@types/react@19.1.8): - dependencies: - '@types/node': 24.1.0 - '@types/react': 19.1.8 - bundle-require@5.1.0(esbuild@0.25.6): dependencies: esbuild: 0.25.6