From 28967881e9470aadd8561387c9ccd0125021d552 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 1 Apr 2025 20:37:19 -0400 Subject: [PATCH 01/52] WIP --- .../repl/src/lib/workers/bundler/index.ts | 284 ++++++++++-------- 1 file changed, 154 insertions(+), 130 deletions(-) diff --git a/packages/repl/src/lib/workers/bundler/index.ts b/packages/repl/src/lib/workers/bundler/index.ts index 44c0479ecb..300d1c3646 100644 --- a/packages/repl/src/lib/workers/bundler/index.ts +++ b/packages/repl/src/lib/workers/bundler/index.ts @@ -22,12 +22,16 @@ import type { Node } from 'estree'; import { parseTar, type FileDescription } from 'tarparser'; import { max } from './semver'; +interface Package { + meta: any; // package.json contents + files: FileDescription[]; + contents: Record; +} + // hack for magic-string and rollup inline sourcemaps // do not put this into a separate module and import it, would be treeshaken in prod self.window = self; -let packages_url: string; -let svelte_url: string; let version: string; let current_id: number; @@ -35,52 +39,79 @@ let inited = Promise.withResolvers(); let can_use_experimental_async = false; -async function init(v: string, packages_url: string) { - const match = /^(pr|commit|branch)-(.+)/.exec(v); +/** map of `pkg-name@1` -> `1.2.3` */ +const versions = new Map>(); +const packages = new Map>(); - let tarball: FileDescription[] | undefined; +async function resolve_version(name: string, version: string) { + // TODO handle `local` version (i.e. create an endpoint) + + const match = /^(pr|commit|branch)-(.+)/.exec(version); if (match) { - const response = await fetch(`https://pkg.pr.new/svelte@${match[2]}`); + return `https://pkg.pr.new/svelte@${match[2]}`; + } - if (!response.ok) { - throw new Error( - `impossible to fetch the compiler from this ${match[1] === 'pr' ? 'PR' : 'commit'}` - ); - } + const key = `${name}@${version}`; - tarball = await parseTar(await response.arrayBuffer()); + if (!versions.has(key)) { + const promise = fetch(`https://cdn.jsdelivr.net/npm/${key}/package.json`).then(async (r) => { + if (!r.ok) { + versions.delete(key); + throw new Error(await r.text()); + } - const json = tarball.find((file) => file.name === 'package/package.json')!.text; - version = JSON.parse(json).version; + return (await r.json()).version; + }); - svelte_url = `svelte://svelte@${version}`; + versions.set(key, promise); + } - for (const file of tarball) { - const url = `${svelte_url}/${file.name.slice('package/'.length)}`; - FETCH_CACHE.set(url, Promise.resolve({ url, body: file.text })); - } - } else if (v === 'local') { - version = v; - svelte_url = `/svelte`; - } else { - const response = await fetch(`${packages_url}/svelte@${v}/package.json`); - const pkg = await response.json(); - version = pkg.version; - svelte_url = `${packages_url}/svelte@${version}`; + return await versions.get(key); +} + +async function fetch_package(name: string, version: string) { + const key = `${name}@${version}`; + + if (!packages.has(key)) { + const url = `https://registry.npmjs.org/${name}/-/${name.split('/').pop()}-${version}.tgz`; + const promise = fetch(url).then(async (r) => { + if (!r.ok) { + packages.delete(url); + throw new Error(`Failed to fetch ${url}`); + } + + const files = await parseTar(await r.arrayBuffer()); + const contents = Object.fromEntries(files.map((file) => [file.name.slice(8), file])); + + const pkg_json = contents['package.json'].text; + + return { + meta: JSON.parse(pkg_json), + files, + contents + }; + }); + + packages.set(key, promise); } + return packages.get(key); +} + +async function init(v: string) { + version = await resolve_version('svelte', v); console.log(`Using Svelte compiler version ${version}`); + const pkg = await fetch_package('svelte', version); + const entry = version.startsWith('3.') ? 'compiler.js' : version.startsWith('4.') ? 'compiler.cjs' : 'compiler/index.js'; - const compiler = tarball - ? tarball.find((file) => file.name === `package/${entry}`)!.text - : await fetch(`${svelte_url}/${entry}`).then((r) => r.text()); + const compiler = pkg.files.find((file) => file.name === `package/${entry}`)!.text; (0, eval)(compiler + `\n//# sourceURL=${entry}@` + version); @@ -104,8 +135,7 @@ async function init(v: string, packages_url: string) { self.addEventListener('message', async (event: MessageEvent) => { switch (event.data.type) { case 'init': { - packages_url = event.data.packages_url; - init(event.data.svelte_version, packages_url).then(inited.resolve, inited.reject); + init(event.data.svelte_version).then(inited.resolve, inited.reject); break; } @@ -244,8 +274,6 @@ async function resolve_from_pkg( return subpath; } -const versions = Object.create(null); - let previous: { key: string; cache: RollupCache | undefined; @@ -321,120 +349,111 @@ async function get_bundle( async resolveId(importee, importer) { if (uid !== current_id) throw ABORT; - if (importee === 'esm-env') return importee; - - if (importee === shared_file) return importee; - - // importing from another file in REPL - if (local_files_lookup.has(importee) && (!importer || local_files_lookup.has(importer))) + if (importee === 'esm-env') { return importee; - if (local_files_lookup.has(importee + '.js')) return importee + '.js'; - if (local_files_lookup.has(importee + '.json')) return importee + '.json'; + } - // remove trailing slash - if (importee.endsWith('/')) importee = importee.slice(0, -1); + if (importee === shared_file) { + return `virtual://$/${shared_file}`; + } - // importing from a URL - if (/^https?:/.test(importee)) return importee; - - if (importee.startsWith('.')) { - if (importer && local_files_lookup.has(importer)) { - // relative import in a REPL file - // should've matched above otherwise importee doesn't exist - console.error(`Cannot find file "${importee}" imported by "${importer}" in the REPL`); - return; - } else { - // relative import in an external file - const url = new URL(importee, importer).href; - self.postMessage({ type: 'status', uid, message: `resolving ${url}` }); - return await follow_redirects(url, uid); - } - } else { - // fetch from unpkg - self.postMessage({ type: 'status', uid, message: `resolving ${importee}` }); + if (importee === './__entry.js') { + return 'virtual://$/__entry.js'; + } - const match = /^((?:@[^/]+\/)?[^/@]+)(?:@([^/]+))?(\/.+)?$/.exec(importee); - if (!match) { - return console.error(`Invalid import "${importee}"`); - } + // importing from a URL + if (/^[a-z]+:/.test(importee)) { + return importee; + } - const pkg_name = match[1]; + if (importee[0] === '.' && importer.startsWith('virtual:')) { + const url = new URL(importee, importer); - let default_version = 'latest'; + for (const suffix of ['', '.js', '.json']) { + const with_suffix = `.${url.pathname}${suffix}`; + const file = local_files_lookup.get(with_suffix); - if (importer?.startsWith(packages_url)) { - const path = importer.slice(packages_url.length + 1); - const parts = path.split('/').slice(0, 2); - if (!parts[0].startsWith('@')) parts.pop(); + if (file) { + return url.href + suffix; + } + } - const importer_name_and_version = parts.join('/'); - const importer_name = importer_name_and_version.slice( - 0, - importer_name_and_version.indexOf('@', 1) - ); + throw new Error(`Could not resolve ${importee} from ${importer}`); + } - const default_versions = (versions[importer_name_and_version] ??= Object.create(null)); + const importer_match = /^npm:\/\/\$\/((?:@[^/]+\/)?[^/@]+)(?:@([^/]+))?(\/.+)?$/.exec( + importer + ); + const importer_pkg = + importer_match && (await fetch_package(importer_match[1], importer_match[2])); - if (!default_versions[pkg_name]) { - const pkg_json_url = `${packages_url}/${importer_name_and_version}/package.json`; - const pkg_json = (await fetch_if_uncached(pkg_json_url, uid))?.body; - const pkg = JSON.parse(pkg_json ?? '""'); + if (importee[0] === '.') { + const url = new URL(importee, importer); + const path = url.pathname.split('/').slice(2).join('/'); - if (importer_name === pkg_name) { - default_versions[pkg_name] = pkg.version; - } else { - const version = - pkg.devDependencies?.[pkg_name] ?? - pkg.peerDependencies?.[pkg_name] ?? - pkg.dependencies?.[pkg_name]; + for (const suffix of ['', '.js', '.mjs', '.cjs', '/index.js', '/index.mjs', '/index.cjs']) { + const with_suffix = path + suffix; + const file = importer_pkg.contents[with_suffix]; - default_versions[pkg_name] = max(version); - } + if (file && file.type === 'file') { + return url.href + suffix; } - - default_version = default_versions[pkg_name]; } - const pkg_url = - pkg_name === 'svelte' - ? `${svelte_url}/package.json` - : `${packages_url}/${pkg_name}@${match[2] ?? default_version}/package.json`; - const subpath = `.${match[3] ?? ''}`; + throw new Error(`Could not resolve ${importee} from ${importer}`); + } - // if this was imported by one of our files, add it to the `imports` set - if (importer && local_files_lookup.has(importer)) { - imports.add(pkg_name); - } + // bare import + const match = /^((?:@[^/]+\/)?[^/@]+)(?:@([^/]+))?(\/.+)?$/.exec(importee); + if (!match) { + return console.error(`Invalid import "${importee}"`); + } - const fetch_package_info = async (pkg_url: string) => { - try { - const redirected = await follow_redirects(pkg_url, uid); + const pkg_name = match[1]; - if (!redirected) throw new Error(); + let default_version = 'latest'; - const pkg_json = (await fetch_if_uncached(redirected, uid))?.body; - const pkg = JSON.parse(pkg_json ?? '""'); + if (importer_pkg) { + default_version = + importer_pkg.meta.name === pkg_name + ? importer_pkg.meta.version + : max( + importer_pkg.meta.devDependencies?.[pkg_name] ?? + importer_pkg.meta.peerDependencies?.[pkg_name] ?? + importer_pkg.meta.dependencies?.[pkg_name] + ); + } - const pkg_url_base = redirected.replace(/\/package\.json$/, ''); + const version = await resolve_version(match[1], match[2] ?? default_version); - return { - pkg, - pkg_url_base - }; - } catch (_e) { - throw new Error(`Error fetching "${pkg_name}" from unpkg. Does the package exist?`); - } - }; + const pkg = await fetch_package(pkg_name, version); - const { pkg, pkg_url_base } = await fetch_package_info(pkg_url); + let subpath = '.' + (match[3] ?? ''); + if (pkg.meta.exports) { try { - const resolved_id = await resolve_from_pkg(pkg, subpath, uid, pkg_url_base); - return new URL(resolved_id + '', `${pkg_url_base}/`).href; - } catch (reason) { - throw new Error(`Cannot import "${importee}": ${reason}.`); + const resolved = resolve.exports(pkg.meta, subpath ?? '.', { + browser: true, + conditions: ['svelte', 'module', 'browser', 'development'] + }); + + subpath = resolved?.[0]; + } catch { + console.log({ importee, importer, pkg_name, version, subpath }); + throw `no matched export path was found in "${pkg_name}/package.json"`; } } + + for (const suffix of ['', '.js', '.mjs', '.cjs', '/index.js', '/index.mjs', '/index.cjs']) { + const with_suffix = subpath.slice(2) + suffix; + const file = pkg.contents[with_suffix]; + + if (file && file.type === 'file') { + return `npm://$/${pkg_name}@${version}/${with_suffix}`; + } + } + + throw new Error(`Could not resolve ${pkg_name}@${version}`); }, async load(resolved) { if (uid !== current_id) throw ABORT; @@ -443,17 +462,22 @@ async function get_bundle( return `export const BROWSER = true; export const DEV = true`; } - const cached_file = local_files_lookup.get(resolved); - if (cached_file) { - return cached_file.contents; + if (resolved.startsWith('virtual://$/')) { + const file = local_files_lookup.get(`./${resolved.slice('virtual://$/'.length)}`)!; + return file.contents; } - if (!FETCH_CACHE.has(resolved)) { - self.postMessage({ type: 'status', uid, message: `fetching ${resolved}` }); + if (resolved.startsWith('npm:')) { + let [, name, version, subpath = ''] = + /^npm:\/\/\$\/((?:@[^/]+\/)?[^/@]+)(?:@([^/]+))?\/(.+)$/.exec(resolved)!; + + const pkg = await fetch_package(name, version); + + const file = pkg.contents[subpath]; + if (file) return file.text; } - const res = await fetch_if_uncached(resolved, uid); - return res?.body; + throw new Error(`Could not load ${resolved}`); }, transform(code, id) { if (uid !== current_id) throw ABORT; @@ -671,7 +695,7 @@ async function bundle({ text: true }); - lookup.set(shared_file, { + lookup.set(`./${shared_file}`, { type: 'file', name: shared_file, basename: shared_file, From 4534595a5a54c19995f5bdf850a9dcf15e51e357 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 1 Apr 2025 20:42:07 -0400 Subject: [PATCH 02/52] fix --- packages/repl/src/lib/workers/bundler/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/repl/src/lib/workers/bundler/index.ts b/packages/repl/src/lib/workers/bundler/index.ts index 300d1c3646..0d8f8dedb7 100644 --- a/packages/repl/src/lib/workers/bundler/index.ts +++ b/packages/repl/src/lib/workers/bundler/index.ts @@ -389,7 +389,10 @@ async function get_bundle( if (importee[0] === '.') { const url = new URL(importee, importer); - const path = url.pathname.split('/').slice(2).join('/'); + const parts = url.pathname.slice(1).split('/'); + if (parts[0][0] === '@') parts.shift(); + parts.shift(); + const path = parts.join('/'); for (const suffix of ['', '.js', '.mjs', '.cjs', '/index.js', '/index.mjs', '/index.cjs']) { const with_suffix = path + suffix; From bd1e16387104c6cdef14ec445b876bc45b6ee704 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 1 Apr 2025 21:00:58 -0400 Subject: [PATCH 03/52] tidy up --- .../repl/src/lib/workers/bundler/index.ts | 217 ++++++------------ 1 file changed, 75 insertions(+), 142 deletions(-) diff --git a/packages/repl/src/lib/workers/bundler/index.ts b/packages/repl/src/lib/workers/bundler/index.ts index 0d8f8dedb7..6866042d3c 100644 --- a/packages/repl/src/lib/workers/bundler/index.ts +++ b/packages/repl/src/lib/workers/bundler/index.ts @@ -1,7 +1,6 @@ import '@sveltejs/site-kit/polyfills'; import { walk } from 'zimmerframe'; import '../patch_window'; -import { sleep } from '../../utils'; import { rollup } from '@rollup/browser'; import { DEV } from 'esm-env'; import * as resolve from 'resolve.exports'; @@ -99,6 +98,77 @@ async function fetch_package(name: string, version: string) { return packages.get(key); } +function resolve_subpath(pkg: Package, subpath: string) { + // match legacy Rollup logic — pkg.svelte takes priority over pkg.exports + if (typeof pkg.meta.svelte === 'string' && subpath === '.') { + return pkg.meta.svelte; + } + + // modern + if (pkg.meta.exports) { + try { + const resolved = resolve.exports(pkg.meta, subpath, { + browser: true, + conditions: ['svelte', 'module', 'browser', 'development'] + }); + + return resolved?.[0]; + } catch { + throw `no matched export path was found in "${pkg.meta.name}/package.json"`; + } + } + + // legacy + if (subpath === '.') { + let resolved_id = resolve.legacy(pkg.meta, { + fields: ['browser', 'module', 'main'] + }); + + if (typeof resolved_id === 'object' && !Array.isArray(resolved_id)) { + const subpath = resolved_id['.']; + if (subpath === false) return 'data:text/javascript,export {}'; + + resolved_id = + subpath ?? + resolve.legacy(pkg.meta, { + fields: ['module', 'main'] + }); + } + + if (!resolved_id) { + // last ditch — try to match index.js/index.mjs + if (pkg.contents['index.mjs']) return './index.mjs'; + if (pkg.contents['index.js']) return './index.js'; + + throw `could not find entry point in "${pkg.meta.name}/package.json"`; + } + + return resolved_id; + } + + if (typeof pkg.meta.browser === 'object') { + // this will either return `pkg.browser[subpath]` or `subpath` + return resolve.legacy(pkg, { + browser: subpath + }); + } + + return subpath; +} + +function add_suffix(pkg: Package, path: string) { + for (const suffix of ['', '.js', '.mjs', '.cjs', '/index.js', '/index.mjs', '/index.cjs']) { + const with_suffix = path + suffix; + const file = pkg.contents[with_suffix]; + + if (file && file.type === 'file') { + return `npm://$/${pkg.meta.name}@${pkg.meta.version}/${with_suffix}`; + } + } + + throw new Error(`Could not find ${path} in ${pkg.meta.name}@${pkg.meta.version}`); +} + async function init(v: string) { version = await resolve_version('svelte', v); console.log(`Using Svelte compiler version ${version}`); @@ -171,109 +241,6 @@ self.addEventListener('message', async (event: MessageEvent) const ABORT = { aborted: true }; -const FETCH_CACHE: Map> = new Map(); - -async function fetch_if_uncached(url: string, uid: number) { - if (FETCH_CACHE.has(url)) { - return FETCH_CACHE.get(url); - } - - // TODO: investigate whether this is necessary - await sleep(50); - if (uid !== current_id) throw ABORT; - - const promise = fetch(url) - .then(async (r) => { - if (!r.ok) throw new Error(await r.text()); - - return { - url: r.url, - body: await r.text() - }; - }) - .catch((err) => { - FETCH_CACHE.delete(url); - throw err; - }); - - FETCH_CACHE.set(url, promise); - return promise; -} - -async function follow_redirects(url: string, uid: number) { - const res = await fetch_if_uncached(url, uid); - return res?.url; -} - -async function resolve_from_pkg( - pkg: Record, - subpath: string, - uid: number, - pkg_url_base: string -) { - // match legacy Rollup logic — pkg.svelte takes priority over pkg.exports - if (typeof pkg.svelte === 'string' && subpath === '.') { - return pkg.svelte; - } - - // modern - if (pkg.exports) { - try { - const resolved = resolve.exports(pkg, subpath, { - browser: true, - conditions: ['svelte', 'module', 'browser', 'development'] - }); - - return resolved?.[0]; - } catch { - throw `no matched export path was found in "${pkg.name}/package.json"`; - } - } - - // legacy - if (subpath === '.') { - let resolved_id = resolve.legacy(pkg, { - fields: ['browser', 'module', 'main'] - }); - - if (typeof resolved_id === 'object' && !Array.isArray(resolved_id)) { - const subpath = resolved_id['.']; - if (subpath === false) return 'data:text/javascript,export {}'; - - resolved_id = - subpath ?? - resolve.legacy(pkg, { - fields: ['module', 'main'] - }); - } - - if (!resolved_id) { - // last ditch — try to match index.js/index.mjs - for (const index_file of ['index.mjs', 'index.js']) { - try { - const indexUrl = new URL(index_file, `${pkg_url_base}/`).href; - return (await follow_redirects(indexUrl, uid)) ?? ''; - } catch { - // maybe the next option will be successful - } - } - - throw `could not find entry point in "${pkg.name}/package.json"`; - } - - return resolved_id; - } - - if (typeof pkg.browser === 'object') { - // this will either return `pkg.browser[subpath]` or `subpath` - return resolve.legacy(pkg, { - browser: subpath - }); - } - - return subpath; -} - let previous: { key: string; cache: RollupCache | undefined; @@ -394,23 +361,12 @@ async function get_bundle( parts.shift(); const path = parts.join('/'); - for (const suffix of ['', '.js', '.mjs', '.cjs', '/index.js', '/index.mjs', '/index.cjs']) { - const with_suffix = path + suffix; - const file = importer_pkg.contents[with_suffix]; - - if (file && file.type === 'file') { - return url.href + suffix; - } - } - - throw new Error(`Could not resolve ${importee} from ${importer}`); + return add_suffix(importer_pkg, path); } // bare import const match = /^((?:@[^/]+\/)?[^/@]+)(?:@([^/]+))?(\/.+)?$/.exec(importee); - if (!match) { - return console.error(`Invalid import "${importee}"`); - } + if (!match) throw new Error(`Invalid import "${importee}"`); const pkg_name = match[1]; @@ -431,32 +387,9 @@ async function get_bundle( const pkg = await fetch_package(pkg_name, version); - let subpath = '.' + (match[3] ?? ''); - - if (pkg.meta.exports) { - try { - const resolved = resolve.exports(pkg.meta, subpath ?? '.', { - browser: true, - conditions: ['svelte', 'module', 'browser', 'development'] - }); - - subpath = resolved?.[0]; - } catch { - console.log({ importee, importer, pkg_name, version, subpath }); - throw `no matched export path was found in "${pkg_name}/package.json"`; - } - } - - for (const suffix of ['', '.js', '.mjs', '.cjs', '/index.js', '/index.mjs', '/index.cjs']) { - const with_suffix = subpath.slice(2) + suffix; - const file = pkg.contents[with_suffix]; - - if (file && file.type === 'file') { - return `npm://$/${pkg_name}@${version}/${with_suffix}`; - } - } + let subpath = resolve_subpath(pkg, '.' + (match[3] ?? '')); - throw new Error(`Could not resolve ${pkg_name}@${version}`); + return add_suffix(pkg, subpath.slice(2)); }, async load(resolved) { if (uid !== current_id) throw ABORT; From d75add226aeddfd8ee938e051067a3b18abb85eb Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 1 Apr 2025 21:04:13 -0400 Subject: [PATCH 04/52] tidy up --- packages/repl/src/lib/workers/bundler/index.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/repl/src/lib/workers/bundler/index.ts b/packages/repl/src/lib/workers/bundler/index.ts index 6866042d3c..3383424b78 100644 --- a/packages/repl/src/lib/workers/bundler/index.ts +++ b/packages/repl/src/lib/workers/bundler/index.ts @@ -31,6 +31,9 @@ interface Package { // do not put this into a separate module and import it, would be treeshaken in prod self.window = self; +const VIRTUAL = 'virtual://$'; +const NPM = 'npm://$'; + let version: string; let current_id: number; @@ -162,7 +165,7 @@ function add_suffix(pkg: Package, path: string) { const file = pkg.contents[with_suffix]; if (file && file.type === 'file') { - return `npm://$/${pkg.meta.name}@${pkg.meta.version}/${with_suffix}`; + return `${NPM}/${pkg.meta.name}@${pkg.meta.version}/${with_suffix}`; } } @@ -321,11 +324,11 @@ async function get_bundle( } if (importee === shared_file) { - return `virtual://$/${shared_file}`; + return `${VIRTUAL}/${shared_file}`; } if (importee === './__entry.js') { - return 'virtual://$/__entry.js'; + return `${VIRTUAL}/__entry.js`; } // importing from a URL @@ -333,7 +336,7 @@ async function get_bundle( return importee; } - if (importee[0] === '.' && importer.startsWith('virtual:')) { + if (importee[0] === '.' && importer.startsWith(VIRTUAL)) { const url = new URL(importee, importer); for (const suffix of ['', '.js', '.json']) { @@ -398,12 +401,12 @@ async function get_bundle( return `export const BROWSER = true; export const DEV = true`; } - if (resolved.startsWith('virtual://$/')) { - const file = local_files_lookup.get(`./${resolved.slice('virtual://$/'.length)}`)!; + if (resolved.startsWith(VIRTUAL)) { + const file = local_files_lookup.get(`./${resolved.slice(VIRTUAL.length + 1)}`)!; return file.contents; } - if (resolved.startsWith('npm:')) { + if (resolved.startsWith(NPM)) { let [, name, version, subpath = ''] = /^npm:\/\/\$\/((?:@[^/]+\/)?[^/@]+)(?:@([^/]+))?\/(.+)$/.exec(resolved)!; From 8895748c26c8705ff3e4c0d0db226e84b6272ed2 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 1 Apr 2025 21:08:18 -0400 Subject: [PATCH 05/52] put npm stuff in separate file --- .../repl/src/lib/workers/bundler/constants.ts | 2 + .../repl/src/lib/workers/bundler/index.ts | 148 +----------------- packages/repl/src/lib/workers/bundler/npm.ts | 140 +++++++++++++++++ 3 files changed, 146 insertions(+), 144 deletions(-) create mode 100644 packages/repl/src/lib/workers/bundler/constants.ts create mode 100644 packages/repl/src/lib/workers/bundler/npm.ts diff --git a/packages/repl/src/lib/workers/bundler/constants.ts b/packages/repl/src/lib/workers/bundler/constants.ts new file mode 100644 index 0000000000..dd2fad619f --- /dev/null +++ b/packages/repl/src/lib/workers/bundler/constants.ts @@ -0,0 +1,2 @@ +export const VIRTUAL = 'virtual://$'; +export const NPM = 'npm://$'; diff --git a/packages/repl/src/lib/workers/bundler/index.ts b/packages/repl/src/lib/workers/bundler/index.ts index 3383424b78..ab9f43b1c4 100644 --- a/packages/repl/src/lib/workers/bundler/index.ts +++ b/packages/repl/src/lib/workers/bundler/index.ts @@ -3,7 +3,6 @@ import { walk } from 'zimmerframe'; import '../patch_window'; import { rollup } from '@rollup/browser'; import { DEV } from 'esm-env'; -import * as resolve from 'resolve.exports'; import commonjs from './plugins/commonjs'; import glsl from './plugins/glsl'; import json from './plugins/json'; @@ -18,22 +17,14 @@ import type { Warning } from '../../types'; import type { CompileError, CompileResult } from 'svelte/compiler'; import type { File } from 'editor'; import type { Node } from 'estree'; -import { parseTar, type FileDescription } from 'tarparser'; import { max } from './semver'; - -interface Package { - meta: any; // package.json contents - files: FileDescription[]; - contents: Record; -} +import { NPM, VIRTUAL } from './constants'; +import { add_suffix, fetch_package, resolve_subpath, resolve_version } from './npm'; // hack for magic-string and rollup inline sourcemaps // do not put this into a separate module and import it, would be treeshaken in prod self.window = self; -const VIRTUAL = 'virtual://$'; -const NPM = 'npm://$'; - let version: string; let current_id: number; @@ -41,137 +32,6 @@ let inited = Promise.withResolvers(); let can_use_experimental_async = false; -/** map of `pkg-name@1` -> `1.2.3` */ -const versions = new Map>(); -const packages = new Map>(); - -async function resolve_version(name: string, version: string) { - // TODO handle `local` version (i.e. create an endpoint) - - const match = /^(pr|commit|branch)-(.+)/.exec(version); - - if (match) { - return `https://pkg.pr.new/svelte@${match[2]}`; - } - - const key = `${name}@${version}`; - - if (!versions.has(key)) { - const promise = fetch(`https://cdn.jsdelivr.net/npm/${key}/package.json`).then(async (r) => { - if (!r.ok) { - versions.delete(key); - throw new Error(await r.text()); - } - - return (await r.json()).version; - }); - - versions.set(key, promise); - } - - return await versions.get(key); -} - -async function fetch_package(name: string, version: string) { - const key = `${name}@${version}`; - - if (!packages.has(key)) { - const url = `https://registry.npmjs.org/${name}/-/${name.split('/').pop()}-${version}.tgz`; - const promise = fetch(url).then(async (r) => { - if (!r.ok) { - packages.delete(url); - throw new Error(`Failed to fetch ${url}`); - } - - const files = await parseTar(await r.arrayBuffer()); - const contents = Object.fromEntries(files.map((file) => [file.name.slice(8), file])); - - const pkg_json = contents['package.json'].text; - - return { - meta: JSON.parse(pkg_json), - files, - contents - }; - }); - - packages.set(key, promise); - } - - return packages.get(key); -} - -function resolve_subpath(pkg: Package, subpath: string) { - // match legacy Rollup logic — pkg.svelte takes priority over pkg.exports - if (typeof pkg.meta.svelte === 'string' && subpath === '.') { - return pkg.meta.svelte; - } - - // modern - if (pkg.meta.exports) { - try { - const resolved = resolve.exports(pkg.meta, subpath, { - browser: true, - conditions: ['svelte', 'module', 'browser', 'development'] - }); - - return resolved?.[0]; - } catch { - throw `no matched export path was found in "${pkg.meta.name}/package.json"`; - } - } - - // legacy - if (subpath === '.') { - let resolved_id = resolve.legacy(pkg.meta, { - fields: ['browser', 'module', 'main'] - }); - - if (typeof resolved_id === 'object' && !Array.isArray(resolved_id)) { - const subpath = resolved_id['.']; - if (subpath === false) return 'data:text/javascript,export {}'; - - resolved_id = - subpath ?? - resolve.legacy(pkg.meta, { - fields: ['module', 'main'] - }); - } - - if (!resolved_id) { - // last ditch — try to match index.js/index.mjs - if (pkg.contents['index.mjs']) return './index.mjs'; - if (pkg.contents['index.js']) return './index.js'; - - throw `could not find entry point in "${pkg.meta.name}/package.json"`; - } - - return resolved_id; - } - - if (typeof pkg.meta.browser === 'object') { - // this will either return `pkg.browser[subpath]` or `subpath` - return resolve.legacy(pkg, { - browser: subpath - }); - } - - return subpath; -} - -function add_suffix(pkg: Package, path: string) { - for (const suffix of ['', '.js', '.mjs', '.cjs', '/index.js', '/index.mjs', '/index.cjs']) { - const with_suffix = path + suffix; - const file = pkg.contents[with_suffix]; - - if (file && file.type === 'file') { - return `${NPM}/${pkg.meta.name}@${pkg.meta.version}/${with_suffix}`; - } - } - - throw new Error(`Could not find ${path} in ${pkg.meta.name}@${pkg.meta.version}`); -} - async function init(v: string) { version = await resolve_version('svelte', v); console.log(`Using Svelte compiler version ${version}`); @@ -546,12 +406,12 @@ async function get_bundle( name: 'tailwind-extract', transform(code, id) { // TODO tidy this up - if (id.startsWith(svelte_url)) return; + if (id.startsWith(`${NPM}/svelte@`)) return; + if (id.startsWith(`${NPM}/clsx@`)) return; if (id.endsWith('.svelte')) return; if (id === './__entry.js') return; if (id === 'esm-env') return; if (id === shared_file) return; - if (id.startsWith('https://unpkg.com/clsx@')) return; add_tailwind_candidates(this.parse(code)); } diff --git a/packages/repl/src/lib/workers/bundler/npm.ts b/packages/repl/src/lib/workers/bundler/npm.ts new file mode 100644 index 0000000000..831a46f891 --- /dev/null +++ b/packages/repl/src/lib/workers/bundler/npm.ts @@ -0,0 +1,140 @@ +import * as resolve from 'resolve.exports'; +import { parseTar, type FileDescription } from 'tarparser'; +import { NPM } from './constants'; + +interface Package { + meta: any; // package.json contents + files: FileDescription[]; + contents: Record; +} + +/** map of `pkg-name@1` -> `1.2.3` */ +const versions = new Map>(); +const packages = new Map>(); + +export async function resolve_version(name: string, version: string) { + // TODO handle `local` version (i.e. create an endpoint) + + const match = /^(pr|commit|branch)-(.+)/.exec(version); + + if (match) { + return `https://pkg.pr.new/svelte@${match[2]}`; + } + + const key = `${name}@${version}`; + + if (!versions.has(key)) { + const promise = fetch(`https://cdn.jsdelivr.net/npm/${key}/package.json`).then(async (r) => { + if (!r.ok) { + versions.delete(key); + throw new Error(await r.text()); + } + + return (await r.json()).version; + }); + + versions.set(key, promise); + } + + return await versions.get(key); +} + +export async function fetch_package(name: string, version: string) { + const key = `${name}@${version}`; + + if (!packages.has(key)) { + const url = `https://registry.npmjs.org/${name}/-/${name.split('/').pop()}-${version}.tgz`; + const promise = fetch(url).then(async (r) => { + if (!r.ok) { + packages.delete(url); + throw new Error(`Failed to fetch ${url}`); + } + + const files = await parseTar(await r.arrayBuffer()); + const contents = Object.fromEntries(files.map((file) => [file.name.slice(8), file])); + + const pkg_json = contents['package.json'].text; + + return { + meta: JSON.parse(pkg_json), + files, + contents + }; + }); + + packages.set(key, promise); + } + + return packages.get(key); +} + +export function resolve_subpath(pkg: Package, subpath: string) { + // match legacy Rollup logic — pkg.svelte takes priority over pkg.exports + if (typeof pkg.meta.svelte === 'string' && subpath === '.') { + return pkg.meta.svelte; + } + + // modern + if (pkg.meta.exports) { + try { + const resolved = resolve.exports(pkg.meta, subpath, { + browser: true, + conditions: ['svelte', 'module', 'browser', 'development'] + }); + + return resolved?.[0]; + } catch { + throw `no matched export path was found in "${pkg.meta.name}/package.json"`; + } + } + + // legacy + if (subpath === '.') { + let resolved_id = resolve.legacy(pkg.meta, { + fields: ['browser', 'module', 'main'] + }); + + if (typeof resolved_id === 'object' && !Array.isArray(resolved_id)) { + const subpath = resolved_id['.']; + if (subpath === false) return 'data:text/javascript,export {}'; + + resolved_id = + subpath ?? + resolve.legacy(pkg.meta, { + fields: ['module', 'main'] + }); + } + + if (!resolved_id) { + // last ditch — try to match index.js/index.mjs + if (pkg.contents['index.mjs']) return './index.mjs'; + if (pkg.contents['index.js']) return './index.js'; + + throw `could not find entry point in "${pkg.meta.name}/package.json"`; + } + + return resolved_id; + } + + if (typeof pkg.meta.browser === 'object') { + // this will either return `pkg.browser[subpath]` or `subpath` + return resolve.legacy(pkg, { + browser: subpath + }); + } + + return subpath; +} + +export function add_suffix(pkg: Package, path: string) { + for (const suffix of ['', '.js', '.mjs', '.cjs', '/index.js', '/index.mjs', '/index.cjs']) { + const with_suffix = path + suffix; + const file = pkg.contents[with_suffix]; + + if (file && file.type === 'file') { + return `${NPM}/${pkg.meta.name}@${pkg.meta.version}/${with_suffix}`; + } + } + + throw new Error(`Could not find ${path} in ${pkg.meta.name}@${pkg.meta.version}`); +} From 5d3da72b8e42c2ab39ac437c4d6bc9ed71f7955d Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 1 Apr 2025 21:14:23 -0400 Subject: [PATCH 06/52] tidy up --- packages/repl/src/lib/workers/bundler/index.ts | 2 +- packages/repl/src/lib/workers/bundler/npm.ts | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/repl/src/lib/workers/bundler/index.ts b/packages/repl/src/lib/workers/bundler/index.ts index ab9f43b1c4..0811c5b216 100644 --- a/packages/repl/src/lib/workers/bundler/index.ts +++ b/packages/repl/src/lib/workers/bundler/index.ts @@ -44,7 +44,7 @@ async function init(v: string) { ? 'compiler.cjs' : 'compiler/index.js'; - const compiler = pkg.files.find((file) => file.name === `package/${entry}`)!.text; + const compiler = pkg.contents[entry].text; (0, eval)(compiler + `\n//# sourceURL=${entry}@` + version); diff --git a/packages/repl/src/lib/workers/bundler/npm.ts b/packages/repl/src/lib/workers/bundler/npm.ts index 831a46f891..565bf6c418 100644 --- a/packages/repl/src/lib/workers/bundler/npm.ts +++ b/packages/repl/src/lib/workers/bundler/npm.ts @@ -4,7 +4,6 @@ import { NPM } from './constants'; interface Package { meta: any; // package.json contents - files: FileDescription[]; contents: Record; } @@ -50,16 +49,17 @@ export async function fetch_package(name: string, version: string) { throw new Error(`Failed to fetch ${url}`); } - const files = await parseTar(await r.arrayBuffer()); - const contents = Object.fromEntries(files.map((file) => [file.name.slice(8), file])); + const contents = {}; - const pkg_json = contents['package.json'].text; + for (const file of await parseTar(await r.arrayBuffer())) { + if (file.type === 'file') { + contents[file.name.slice(8)] = file; // remove `package/` prefix + } + } + + const meta = JSON.parse(contents['package.json'].text); - return { - meta: JSON.parse(pkg_json), - files, - contents - }; + return { meta, contents }; }); packages.set(key, promise); From b21c86fc2c0d46c0c7ccedb3397d1364fe7ca749 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 1 Apr 2025 21:19:14 -0400 Subject: [PATCH 07/52] remove ./ --- packages/repl/src/lib/workers/bundler/index.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/repl/src/lib/workers/bundler/index.ts b/packages/repl/src/lib/workers/bundler/index.ts index 0811c5b216..aa197e8cb9 100644 --- a/packages/repl/src/lib/workers/bundler/index.ts +++ b/packages/repl/src/lib/workers/bundler/index.ts @@ -200,7 +200,7 @@ async function get_bundle( const url = new URL(importee, importer); for (const suffix of ['', '.js', '.json']) { - const with_suffix = `.${url.pathname}${suffix}`; + const with_suffix = `${url.pathname.slice(1)}${suffix}`; const file = local_files_lookup.get(with_suffix); if (file) { @@ -262,7 +262,7 @@ async function get_bundle( } if (resolved.startsWith(VIRTUAL)) { - const file = local_files_lookup.get(`./${resolved.slice(VIRTUAL.length + 1)}`)!; + const file = local_files_lookup.get(resolved.slice(VIRTUAL.length + 1))!; return file.contents; } @@ -321,7 +321,7 @@ async function get_bundle( if (result.css?.code) { // resolve local files by inlining them result.css.code = result.css.code.replace( - /url\(['"]?(\..+?\.(svg|webp|png))['"]?\)/g, + /url\(['"]?\.\/(.+?\.(svg|webp|png))['"]?\)/g, (match, $1, $2) => { if (local_files_lookup.has($1)) { if ($2 === 'svg') { @@ -461,7 +461,7 @@ async function bundle({ const lookup: Map = new Map(); - lookup.set('./__entry.js', { + lookup.set('__entry.js', { type: 'file', name: '__entry.js', basename: '__entry.js', @@ -494,7 +494,7 @@ async function bundle({ text: true }); - lookup.set(`./${shared_file}`, { + lookup.set(shared_file, { type: 'file', name: shared_file, basename: shared_file, @@ -505,8 +505,7 @@ async function bundle({ }); files.forEach((file) => { - const path = `./${file.name}`; - lookup.set(path, file); + lookup.set(file.name, file); }); let client: Awaited> = await get_bundle( From 76db04880174dac7b5b33e86949f8c6b4cdff8c8 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 1 Apr 2025 21:38:19 -0400 Subject: [PATCH 08/52] tidy up --- .../repl/src/lib/workers/bundler/constants.ts | 4 + .../repl/src/lib/workers/bundler/index.ts | 100 +++++++++--------- 2 files changed, 53 insertions(+), 51 deletions(-) diff --git a/packages/repl/src/lib/workers/bundler/constants.ts b/packages/repl/src/lib/workers/bundler/constants.ts index dd2fad619f..938a0bd225 100644 --- a/packages/repl/src/lib/workers/bundler/constants.ts +++ b/packages/repl/src/lib/workers/bundler/constants.ts @@ -1,2 +1,6 @@ export const VIRTUAL = 'virtual://$'; export const NPM = 'npm://$'; + +export const ENTRYPOINT = '__entry.js'; +export const STYLES = '__styles.js'; +export const ESM_ENV = '__esm-env.js'; diff --git a/packages/repl/src/lib/workers/bundler/index.ts b/packages/repl/src/lib/workers/bundler/index.ts index aa197e8cb9..08d252cdfe 100644 --- a/packages/repl/src/lib/workers/bundler/index.ts +++ b/packages/repl/src/lib/workers/bundler/index.ts @@ -18,7 +18,7 @@ import type { CompileError, CompileResult } from 'svelte/compiler'; import type { File } from 'editor'; import type { Node } from 'estree'; import { max } from './semver'; -import { NPM, VIRTUAL } from './constants'; +import { ENTRYPOINT, ESM_ENV, NPM, STYLES, VIRTUAL } from './constants'; import { add_suffix, fetch_package, resolve_subpath, resolve_version } from './npm'; // hack for magic-string and rollup inline sourcemaps @@ -141,7 +141,7 @@ async function init_tailwind() { async function get_bundle( uid: number, mode: 'client' | 'server', - local_files_lookup: Map, + virtual: Map, options: BundleOptions ) { let bundle; @@ -179,29 +179,22 @@ async function get_bundle( async resolveId(importee, importer) { if (uid !== current_id) throw ABORT; - if (importee === 'esm-env') { - return importee; - } + // entrypoint + if (!importer) return `${VIRTUAL}/${ENTRYPOINT}`; - if (importee === shared_file) { - return `${VIRTUAL}/${shared_file}`; - } - - if (importee === './__entry.js') { - return `${VIRTUAL}/__entry.js`; - } + // special case + if (importee === 'esm-env') return `${VIRTUAL}/${ESM_ENV}`; // importing from a URL - if (/^[a-z]+:/.test(importee)) { - return importee; - } + if (/^[a-z]+:/.test(importee)) return importee; + // importing a local file -> `virtual://$/` if (importee[0] === '.' && importer.startsWith(VIRTUAL)) { const url = new URL(importee, importer); for (const suffix of ['', '.js', '.json']) { const with_suffix = `${url.pathname.slice(1)}${suffix}`; - const file = local_files_lookup.get(with_suffix); + const file = virtual.get(with_suffix); if (file) { return url.href + suffix; @@ -217,6 +210,7 @@ async function get_bundle( const importer_pkg = importer_match && (await fetch_package(importer_match[1], importer_match[2])); + // external package importing from itself if (importee[0] === '.') { const url = new URL(importee, importer); const parts = url.pathname.slice(1).split('/'); @@ -227,7 +221,7 @@ async function get_bundle( return add_suffix(importer_pkg, path); } - // bare import + // importing an external package -> `npm://$/@/` const match = /^((?:@[^/]+\/)?[^/@]+)(?:@([^/]+))?(\/.+)?$/.exec(importee); if (!match) throw new Error(`Invalid import "${importee}"`); @@ -236,38 +230,33 @@ async function get_bundle( let default_version = 'latest'; if (importer_pkg) { - default_version = - importer_pkg.meta.name === pkg_name - ? importer_pkg.meta.version - : max( - importer_pkg.meta.devDependencies?.[pkg_name] ?? - importer_pkg.meta.peerDependencies?.[pkg_name] ?? - importer_pkg.meta.dependencies?.[pkg_name] - ); + if (importer_pkg.meta.name === pkg_name) { + default_version = importer_pkg.meta.version; + } else { + default_version = max( + importer_pkg.meta.devDependencies?.[pkg_name] ?? + importer_pkg.meta.peerDependencies?.[pkg_name] ?? + importer_pkg.meta.dependencies?.[pkg_name] + ); + } } const version = await resolve_version(match[1], match[2] ?? default_version); - const pkg = await fetch_package(pkg_name, version); - - let subpath = resolve_subpath(pkg, '.' + (match[3] ?? '')); + const subpath = resolve_subpath(pkg, '.' + (match[3] ?? '')); return add_suffix(pkg, subpath.slice(2)); }, async load(resolved) { if (uid !== current_id) throw ABORT; - if (resolved === 'esm-env') { - return `export const BROWSER = true; export const DEV = true`; - } - if (resolved.startsWith(VIRTUAL)) { - const file = local_files_lookup.get(resolved.slice(VIRTUAL.length + 1))!; + const file = virtual.get(resolved.slice(VIRTUAL.length + 1))!; return file.contents; } if (resolved.startsWith(NPM)) { - let [, name, version, subpath = ''] = + let [, name, version, subpath] = /^npm:\/\/\$\/((?:@[^/]+\/)?[^/@]+)(?:@([^/]+))?\/(.+)$/.exec(resolved)!; const pkg = await fetch_package(name, version); @@ -323,11 +312,11 @@ async function get_bundle( result.css.code = result.css.code.replace( /url\(['"]?\.\/(.+?\.(svg|webp|png))['"]?\)/g, (match, $1, $2) => { - if (local_files_lookup.has($1)) { + if (virtual.has($1)) { if ($2 === 'svg') { - return `url('data:image/svg+xml;base64,${btoa(local_files_lookup.get($1)!.contents)}')`; + return `url('data:image/svg+xml;base64,${btoa(virtual.get($1)!.contents)}')`; } else { - return `url('data:image/${$2};base64,${local_files_lookup.get($1)!.contents}')`; + return `url('data:image/${$2};base64,${virtual.get($1)!.contents}')`; } } else { return match; @@ -338,7 +327,7 @@ async function get_bundle( result.js.code += '\n\n' + ` - import { styles as $$_styles } from '${shared_file}'; + import { styles as $$_styles } from './${STYLES}'; const $$__style = document.createElement('style'); $$__style.textContent = ${JSON.stringify(result.css.code)}; document.head.append($$__style); @@ -408,10 +397,10 @@ async function get_bundle( // TODO tidy this up if (id.startsWith(`${NPM}/svelte@`)) return; if (id.startsWith(`${NPM}/clsx@`)) return; + if (id === `${VIRTUAL}/${ENTRYPOINT}`) return; + if (id === `${VIRTUAL}/${STYLES}`) return; + if (id === `${VIRTUAL}/${ESM_ENV}`) return; if (id.endsWith('.svelte')) return; - if (id === './__entry.js') return; - if (id === 'esm-env') return; - if (id === shared_file) return; add_tailwind_candidates(this.parse(code)); } @@ -443,8 +432,6 @@ async function get_bundle( export type BundleResult = ReturnType; -const shared_file = '$$__shared__.js'; - async function bundle({ uid, files, @@ -461,15 +448,15 @@ async function bundle({ const lookup: Map = new Map(); - lookup.set('__entry.js', { + lookup.set(ENTRYPOINT, { type: 'file', - name: '__entry.js', - basename: '__entry.js', + name: ENTRYPOINT, + basename: ENTRYPOINT, contents: version.split('.')[0] >= '5' ? ` import { unmount as u } from 'svelte'; - import { styles } from '${shared_file}'; + import { styles } from './${STYLES}'; export { mount, untrack } from 'svelte'; export {default as App} from './App.svelte'; export function unmount(component) { @@ -478,7 +465,7 @@ async function bundle({ } ` : ` - import { styles } from '${shared_file}'; + import { styles } from './${STYLES}'; export {default as App} from './App.svelte'; export function mount(component, options) { return new component(options); @@ -494,16 +481,27 @@ async function bundle({ text: true }); - lookup.set(shared_file, { + lookup.set(STYLES, { type: 'file', - name: shared_file, - basename: shared_file, + name: STYLES, + basename: STYLES, contents: ` export let styles = []; `, text: true }); + lookup.set(ESM_ENV, { + type: 'file', + name: STYLES, + basename: STYLES, + contents: ` + export const BROWSER = true; + export const DEV = true; + `, + text: true + }); + files.forEach((file) => { lookup.set(file.name, file); }); From 11e0521efd82eddd3161a6b6d36b3e3dc5593f71 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 1 Apr 2025 21:50:57 -0400 Subject: [PATCH 09/52] fix --- packages/repl/src/lib/workers/bundler/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/repl/src/lib/workers/bundler/index.ts b/packages/repl/src/lib/workers/bundler/index.ts index 08d252cdfe..cfcf93155d 100644 --- a/packages/repl/src/lib/workers/bundler/index.ts +++ b/packages/repl/src/lib/workers/bundler/index.ts @@ -327,7 +327,7 @@ async function get_bundle( result.js.code += '\n\n' + ` - import { styles as $$_styles } from './${STYLES}'; + import { styles as $$_styles } from '${VIRTUAL}/${STYLES}'; const $$__style = document.createElement('style'); $$__style.textContent = ${JSON.stringify(result.css.code)}; document.head.append($$__style); @@ -456,7 +456,7 @@ async function bundle({ version.split('.')[0] >= '5' ? ` import { unmount as u } from 'svelte'; - import { styles } from './${STYLES}'; + import { styles } from '${VIRTUAL}/${STYLES}'; export { mount, untrack } from 'svelte'; export {default as App} from './App.svelte'; export function unmount(component) { @@ -465,7 +465,7 @@ async function bundle({ } ` : ` - import { styles } from './${STYLES}'; + import { styles } from '${VIRTUAL}/${STYLES}'; export {default as App} from './App.svelte'; export function mount(component, options) { return new component(options); From bb3ce15093000e9e24fae5572061b5ded30c4c00 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 1 Apr 2025 21:55:49 -0400 Subject: [PATCH 10/52] lint --- packages/repl/src/lib/workers/bundler/index.ts | 2 +- packages/repl/src/lib/workers/bundler/npm.ts | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/repl/src/lib/workers/bundler/index.ts b/packages/repl/src/lib/workers/bundler/index.ts index cfcf93155d..4d109c1370 100644 --- a/packages/repl/src/lib/workers/bundler/index.ts +++ b/packages/repl/src/lib/workers/bundler/index.ts @@ -211,7 +211,7 @@ async function get_bundle( importer_match && (await fetch_package(importer_match[1], importer_match[2])); // external package importing from itself - if (importee[0] === '.') { + if (importer_pkg && importee[0] === '.') { const url = new URL(importee, importer); const parts = url.pathname.slice(1).split('/'); if (parts[0][0] === '@') parts.shift(); diff --git a/packages/repl/src/lib/workers/bundler/npm.ts b/packages/repl/src/lib/workers/bundler/npm.ts index 565bf6c418..808a8a564e 100644 --- a/packages/repl/src/lib/workers/bundler/npm.ts +++ b/packages/repl/src/lib/workers/bundler/npm.ts @@ -11,7 +11,7 @@ interface Package { const versions = new Map>(); const packages = new Map>(); -export async function resolve_version(name: string, version: string) { +export async function resolve_version(name: string, version: string): Promise { // TODO handle `local` version (i.e. create an endpoint) const match = /^(pr|commit|branch)-(.+)/.exec(version); @@ -35,10 +35,10 @@ export async function resolve_version(name: string, version: string) { versions.set(key, promise); } - return await versions.get(key); + return await versions.get(key)!; } -export async function fetch_package(name: string, version: string) { +export async function fetch_package(name: string, version: string): Promise { const key = `${name}@${version}`; if (!packages.has(key)) { @@ -49,7 +49,7 @@ export async function fetch_package(name: string, version: string) { throw new Error(`Failed to fetch ${url}`); } - const contents = {}; + const contents: Record = {}; for (const file of await parseTar(await r.arrayBuffer())) { if (file.type === 'file') { @@ -65,7 +65,7 @@ export async function fetch_package(name: string, version: string) { packages.set(key, promise); } - return packages.get(key); + return packages.get(key)!; } export function resolve_subpath(pkg: Package, subpath: string) { From 088f5f3ed48fe87c00f7daf71c06ec3c30cf21d3 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 2 Apr 2025 08:00:33 -0400 Subject: [PATCH 11/52] fix --- packages/repl/src/lib/workers/bundler/npm.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/repl/src/lib/workers/bundler/npm.ts b/packages/repl/src/lib/workers/bundler/npm.ts index 808a8a564e..d86ccf0bea 100644 --- a/packages/repl/src/lib/workers/bundler/npm.ts +++ b/packages/repl/src/lib/workers/bundler/npm.ts @@ -71,7 +71,7 @@ export async function fetch_package(name: string, version: string): Promise Date: Wed, 2 Apr 2025 08:03:54 -0400 Subject: [PATCH 12/52] always use same svelte version --- packages/repl/src/lib/workers/bundler/index.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/repl/src/lib/workers/bundler/index.ts b/packages/repl/src/lib/workers/bundler/index.ts index 4d109c1370..f21b5b6acb 100644 --- a/packages/repl/src/lib/workers/bundler/index.ts +++ b/packages/repl/src/lib/workers/bundler/index.ts @@ -208,7 +208,11 @@ async function get_bundle( importer ); const importer_pkg = - importer_match && (await fetch_package(importer_match[1], importer_match[2])); + importer_match && + (await fetch_package( + importer_match[1], + importer_match[1] === 'svelte' ? version : importer_match[2] + )); // external package importing from itself if (importer_pkg && importee[0] === '.') { @@ -241,8 +245,8 @@ async function get_bundle( } } - const version = await resolve_version(match[1], match[2] ?? default_version); - const pkg = await fetch_package(pkg_name, version); + const v = await resolve_version(match[1], match[2] ?? default_version); + const pkg = await fetch_package(pkg_name, pkg_name === 'svelte' ? version : v); const subpath = resolve_subpath(pkg, '.' + (match[3] ?? '')); return add_suffix(pkg, subpath.slice(2)); @@ -256,10 +260,11 @@ async function get_bundle( } if (resolved.startsWith(NPM)) { - let [, name, version, subpath] = - /^npm:\/\/\$\/((?:@[^/]+\/)?[^/@]+)(?:@([^/]+))?\/(.+)$/.exec(resolved)!; + let [, name, v, subpath] = /^npm:\/\/\$\/((?:@[^/]+\/)?[^/@]+)(?:@([^/]+))?\/(.+)$/.exec( + resolved + )!; - const pkg = await fetch_package(name, version); + const pkg = await fetch_package(name, name === 'svelte' ? version : v); const file = pkg.contents[subpath]; if (file) return file.text; From f85ecdf53cd19f3fbe853c7b20c49293fb1ce992 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 2 Apr 2025 08:10:53 -0400 Subject: [PATCH 13/52] fix pkg.pr.new versions --- .../routes/(authed)/playground/[id]/+page.svelte | 2 +- packages/repl/src/lib/workers/bundler/npm.ts | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte b/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte index 00579ed7a0..3faf22c2fa 100644 --- a/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte +++ b/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte @@ -23,7 +23,7 @@ // svelte-ignore non_reactive_update let version = page.url.searchParams.get('version') || 'latest'; - let is_pr_or_commit_version = version.startsWith('pr-') || version.startsWith('commit-'); + let is_pr_or_commit_version = /^(pr|commit|branch)-(.+)/.test(version); // Hashed URLs are less safe (we can't delete malicious REPLs), therefore // don't allow links to escape the sandbox restrictions diff --git a/packages/repl/src/lib/workers/bundler/npm.ts b/packages/repl/src/lib/workers/bundler/npm.ts index d86ccf0bea..fdeb4715ab 100644 --- a/packages/repl/src/lib/workers/bundler/npm.ts +++ b/packages/repl/src/lib/workers/bundler/npm.ts @@ -11,13 +11,13 @@ interface Package { const versions = new Map>(); const packages = new Map>(); +const pkg_pr_new_regex = /^(pr|commit|branch)-(.+)/; + export async function resolve_version(name: string, version: string): Promise { // TODO handle `local` version (i.e. create an endpoint) - const match = /^(pr|commit|branch)-(.+)/.exec(version); - - if (match) { - return `https://pkg.pr.new/svelte@${match[2]}`; + if (pkg_pr_new_regex.test(version)) { + return version; } const key = `${name}@${version}`; @@ -42,7 +42,12 @@ export async function fetch_package(name: string, version: string): Promise { if (!r.ok) { packages.delete(url); From 585c65c8f7a973533fe6cc12702a3d940094b0a2 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 2 Apr 2025 08:11:03 -0400 Subject: [PATCH 14/52] use jsDelivr for more stuff --- .../svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte | 2 +- .../src/routes/(authed)/playground/[id]/embed/+page.svelte | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte b/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte index 3faf22c2fa..9cbb88eaad 100644 --- a/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte +++ b/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte @@ -31,7 +31,7 @@ if (version !== 'local' && !is_pr_or_commit_version) { $effect(() => { - fetch(`https://unpkg.com/svelte@${version}/package.json`) + fetch(`https://cdn.jsdelivr.net/npm/svelte@${version}/package.json`) .then((r) => r.json()) .then((pkg) => { if (pkg.version !== version) { diff --git a/apps/svelte.dev/src/routes/(authed)/playground/[id]/embed/+page.svelte b/apps/svelte.dev/src/routes/(authed)/playground/[id]/embed/+page.svelte index ab843d9ad3..acf9a88a70 100644 --- a/apps/svelte.dev/src/routes/(authed)/playground/[id]/embed/+page.svelte +++ b/apps/svelte.dev/src/routes/(authed)/playground/[id]/embed/+page.svelte @@ -17,7 +17,7 @@ if (version !== 'local' && !is_pr_or_commit_version) { $effect(() => { - fetch(`https://unpkg.com/svelte@${version}/package.json`) + fetch(`https://cdn.jsdelivr.net/npm/svelte@${version}/package.json`) .then((r) => r.json()) .then((pkg) => { if (pkg.version !== data.version) { From 5f97c93316c30269923f7758797098cf2a3223d5 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 2 Apr 2025 08:14:20 -0400 Subject: [PATCH 15/52] remove packages_url stuff --- .../tutorial/adapters/rollup/index.svelte.ts | 1 - packages/repl/src/lib/Bundler.ts | 17 ++++++++--------- packages/repl/src/lib/Repl.svelte | 3 --- packages/repl/src/lib/workers/workers.d.ts | 1 - 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/apps/svelte.dev/src/lib/tutorial/adapters/rollup/index.svelte.ts b/apps/svelte.dev/src/lib/tutorial/adapters/rollup/index.svelte.ts index 53e59cfd97..f243cea92c 100644 --- a/apps/svelte.dev/src/lib/tutorial/adapters/rollup/index.svelte.ts +++ b/apps/svelte.dev/src/lib/tutorial/adapters/rollup/index.svelte.ts @@ -23,7 +23,6 @@ export async function create(): Promise { let done = false; bundler = new Bundler({ - packages_url: 'https://unpkg.com', svelte_version: 'latest', onstatus(val) { if (!done && val === null) { diff --git a/packages/repl/src/lib/Bundler.ts b/packages/repl/src/lib/Bundler.ts index a861c2a686..7c4884c5a0 100644 --- a/packages/repl/src/lib/Bundler.ts +++ b/packages/repl/src/lib/Bundler.ts @@ -7,33 +7,31 @@ const workers = new Map(); let uid = 1; export default class Bundler { - hash: string; + svelte_version: string; worker: Worker; handlers: Map void>; constructor({ - packages_url, svelte_version, onstatus, onerror }: { - packages_url: string; svelte_version: string; onstatus: (val: string | null) => void; onerror?: (message: string) => void; }) { - this.hash = `${packages_url}:${svelte_version}`; + this.svelte_version = svelte_version; - if (!workers.has(this.hash)) { + if (!workers.has(svelte_version)) { const worker = new Worker(new URL('./workers/bundler/index', import.meta.url), { type: 'module' }); - worker.postMessage({ type: 'init', packages_url, svelte_version }); - workers.set(this.hash, worker); + worker.postMessage({ type: 'init', svelte_version }); + workers.set(svelte_version, worker); } - this.worker = workers.get(this.hash); + this.worker = workers.get(svelte_version); this.handlers = new Map(); @@ -74,7 +72,8 @@ export default class Bundler { } destroy() { + // TODO this is assymetrical and probably wrong? this.worker.terminate(); - workers.delete(this.hash); + workers.delete(this.svelte_version); } } diff --git a/packages/repl/src/lib/Repl.svelte b/packages/repl/src/lib/Repl.svelte index 85bd3f520b..6b98bfeae6 100644 --- a/packages/repl/src/lib/Repl.svelte +++ b/packages/repl/src/lib/Repl.svelte @@ -11,7 +11,6 @@ import type { Bundle, ReplContext } from './types.js'; interface Props { - packagesUrl?: string; svelteVersion?: string; embedded?: boolean | 'output-only'; orientation?: 'columns' | 'rows'; @@ -27,7 +26,6 @@ } let { - packagesUrl = 'https://unpkg.com', svelteVersion = 'latest', embedded = false, orientation = 'columns', @@ -122,7 +120,6 @@ const bundler = BROWSER ? new Bundler({ - packages_url: packagesUrl, svelte_version: svelteVersion, onstatus: (message) => { if (message) { diff --git a/packages/repl/src/lib/workers/workers.d.ts b/packages/repl/src/lib/workers/workers.d.ts index 59710fa266..d6fe0489a5 100644 --- a/packages/repl/src/lib/workers/workers.d.ts +++ b/packages/repl/src/lib/workers/workers.d.ts @@ -56,7 +56,6 @@ export type BundleMessageData = { uid: number; type: 'init' | 'bundle' | 'status' | 'error'; message: string; - packages_url: string; svelte_version: string; files: File[]; options: BundleOptions; From 632851d90460d924902dffd427a84907b2d4ce51 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 2 Apr 2025 08:21:21 -0400 Subject: [PATCH 16/52] lint --- packages/repl/src/lib/workers/bundler/npm.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/repl/src/lib/workers/bundler/npm.ts b/packages/repl/src/lib/workers/bundler/npm.ts index fdeb4715ab..b5543b623c 100644 --- a/packages/repl/src/lib/workers/bundler/npm.ts +++ b/packages/repl/src/lib/workers/bundler/npm.ts @@ -73,7 +73,7 @@ export async function fetch_package(name: string, version: string): Promise Date: Wed, 2 Apr 2025 08:24:20 -0400 Subject: [PATCH 17/52] gah --- packages/repl/src/lib/workers/bundler/npm.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/repl/src/lib/workers/bundler/npm.ts b/packages/repl/src/lib/workers/bundler/npm.ts index b5543b623c..e6bca013bd 100644 --- a/packages/repl/src/lib/workers/bundler/npm.ts +++ b/packages/repl/src/lib/workers/bundler/npm.ts @@ -87,7 +87,7 @@ export function resolve_subpath(pkg: Package, subpath: string): string { conditions: ['svelte', 'module', 'browser', 'development'] }); - return resolved?.[0]; + return resolved?.[0] as string; } catch { throw new Error( `no matched export path was found for "${subpath}" in "${pkg.meta.name}/package.json"` From 1984aa240466753ca4fc0ccf696f73149a8999e2 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 2 Apr 2025 09:14:10 -0400 Subject: [PATCH 18/52] fix `local` --- .../repl/src/lib/workers/bundler/index.ts | 117 ++++++++++-------- packages/repl/src/lib/workers/bundler/npm.ts | 31 ++++- 2 files changed, 96 insertions(+), 52 deletions(-) diff --git a/packages/repl/src/lib/workers/bundler/index.ts b/packages/repl/src/lib/workers/bundler/index.ts index f21b5b6acb..f4ee54aeb6 100644 --- a/packages/repl/src/lib/workers/bundler/index.ts +++ b/packages/repl/src/lib/workers/bundler/index.ts @@ -19,13 +19,20 @@ import type { File } from 'editor'; import type { Node } from 'estree'; import { max } from './semver'; import { ENTRYPOINT, ESM_ENV, NPM, STYLES, VIRTUAL } from './constants'; -import { add_suffix, fetch_package, resolve_subpath, resolve_version } from './npm'; +import { + add_suffix, + fetch_package, + parse_npm_url, + resolve_local, + resolve_subpath, + resolve_version +} from './npm'; // hack for magic-string and rollup inline sourcemaps // do not put this into a separate module and import it, would be treeshaken in prod self.window = self; -let version: string; +let svelte_version: string; let current_id: number; let inited = Promise.withResolvers(); @@ -33,23 +40,27 @@ let inited = Promise.withResolvers(); let can_use_experimental_async = false; async function init(v: string) { - version = await resolve_version('svelte', v); - console.log(`Using Svelte compiler version ${version}`); + svelte_version = await resolve_version('svelte', v); + console.log(`Using Svelte compiler version ${svelte_version}`); - const pkg = await fetch_package('svelte', version); + if (svelte_version === 'local') { + await import(`${location.origin}/svelte/compiler/index.js`); + } else { + const pkg = await fetch_package('svelte', svelte_version); - const entry = version.startsWith('3.') - ? 'compiler.js' - : version.startsWith('4.') - ? 'compiler.cjs' - : 'compiler/index.js'; + const entry = svelte_version.startsWith('3.') + ? 'compiler.js' + : svelte_version.startsWith('4.') + ? 'compiler.cjs' + : 'compiler/index.js'; - const compiler = pkg.contents[entry].text; + const compiler = pkg.contents[entry].text; - (0, eval)(compiler + `\n//# sourceURL=${entry}@` + version); + (0, eval)(compiler + `\n//# sourceURL=${entry}@` + svelte_version); + } try { - self.svelte.compileModule('', { + svelte.compileModule('', { generate: 'client', // @ts-expect-error experimental: { @@ -188,41 +199,33 @@ async function get_bundle( // importing from a URL if (/^[a-z]+:/.test(importee)) return importee; - // importing a local file -> `virtual://$/` - if (importee[0] === '.' && importer.startsWith(VIRTUAL)) { - const url = new URL(importee, importer); + // importing a relative file + if (importee[0] === '.') { + if (importer.startsWith(VIRTUAL)) { + const url = new URL(importee, importer); - for (const suffix of ['', '.js', '.json']) { - const with_suffix = `${url.pathname.slice(1)}${suffix}`; - const file = virtual.get(with_suffix); + for (const suffix of ['', '.js', '.json']) { + const with_suffix = `${url.pathname.slice(1)}${suffix}`; + const file = virtual.get(with_suffix); - if (file) { - return url.href + suffix; + if (file) { + return url.href + suffix; + } } + + throw new Error(`Could not resolve ${importee} from ${importer}`); } - throw new Error(`Could not resolve ${importee} from ${importer}`); - } + if (importer.startsWith(NPM)) { + const { name, version } = parse_npm_url(importer); + + const pkg = await fetch_package(name, name === 'svelte' ? svelte_version : version); + const path = new URL(importee, importer).pathname.replace(`/${name}@${version}/`, ''); + + return add_suffix(pkg, path); + } - const importer_match = /^npm:\/\/\$\/((?:@[^/]+\/)?[^/@]+)(?:@([^/]+))?(\/.+)?$/.exec( - importer - ); - const importer_pkg = - importer_match && - (await fetch_package( - importer_match[1], - importer_match[1] === 'svelte' ? version : importer_match[2] - )); - - // external package importing from itself - if (importer_pkg && importee[0] === '.') { - const url = new URL(importee, importer); - const parts = url.pathname.slice(1).split('/'); - if (parts[0][0] === '@') parts.shift(); - parts.shift(); - const path = parts.join('/'); - - return add_suffix(importer_pkg, path); + return new URL(importee, importer).href; } // importing an external package -> `npm://$/@/` @@ -231,22 +234,31 @@ async function get_bundle( const pkg_name = match[1]; + if (pkg_name === 'svelte' && svelte_version === 'local') { + return await resolve_local(importee); + } + let default_version = 'latest'; - if (importer_pkg) { - if (importer_pkg.meta.name === pkg_name) { - default_version = importer_pkg.meta.version; + if (importer.startsWith(NPM)) { + // use the version specified in importer's package.json, not `latest` + const { name, version } = parse_npm_url(importer); + + const { meta } = await fetch_package(name, name === 'svelte' ? svelte_version : version); + + if (meta.name === pkg_name) { + default_version = meta.version; } else { default_version = max( - importer_pkg.meta.devDependencies?.[pkg_name] ?? - importer_pkg.meta.peerDependencies?.[pkg_name] ?? - importer_pkg.meta.dependencies?.[pkg_name] + meta.devDependencies?.[pkg_name] ?? + meta.peerDependencies?.[pkg_name] ?? + meta.dependencies?.[pkg_name] ); } } const v = await resolve_version(match[1], match[2] ?? default_version); - const pkg = await fetch_package(pkg_name, pkg_name === 'svelte' ? version : v); + const pkg = await fetch_package(pkg_name, pkg_name === 'svelte' ? svelte_version : v); const subpath = resolve_subpath(pkg, '.' + (match[3] ?? '')); return add_suffix(pkg, subpath.slice(2)); @@ -264,12 +276,15 @@ async function get_bundle( resolved )!; - const pkg = await fetch_package(name, name === 'svelte' ? version : v); + const pkg = await fetch_package(name, name === 'svelte' ? svelte_version : v); const file = pkg.contents[subpath]; if (file) return file.text; } + const response = await fetch(resolved); + if (response.ok) return response.text(); + throw new Error(`Could not load ${resolved}`); }, transform(code, id) { @@ -458,7 +473,7 @@ async function bundle({ name: ENTRYPOINT, basename: ENTRYPOINT, contents: - version.split('.')[0] >= '5' + svelte_version.split('.')[0] >= '5' ? ` import { unmount as u } from 'svelte'; import { styles } from '${VIRTUAL}/${STYLES}'; diff --git a/packages/repl/src/lib/workers/bundler/npm.ts b/packages/repl/src/lib/workers/bundler/npm.ts index e6bca013bd..5ea59787b8 100644 --- a/packages/repl/src/lib/workers/bundler/npm.ts +++ b/packages/repl/src/lib/workers/bundler/npm.ts @@ -14,7 +14,9 @@ const packages = new Map>(); const pkg_pr_new_regex = /^(pr|commit|branch)-(.+)/; export async function resolve_version(name: string, version: string): Promise { - // TODO handle `local` version (i.e. create an endpoint) + if (name === 'svelte' && version === 'local') { + return version; + } if (pkg_pr_new_regex.test(version)) { return version; @@ -145,3 +147,30 @@ export function add_suffix(pkg: Package, path: string) { throw new Error(`Could not find ${path} in ${pkg.meta.name}@${pkg.meta.version}`); } + +const LOCAL_PKG_URL = `${location.origin}/svelte/package.json`; +let local_svelte_pkg: Promise; + +export async function resolve_local(specifier: string) { + const pkg = await (local_svelte_pkg ??= fetch(LOCAL_PKG_URL).then((r) => r.json())); + + const subpath = resolve.exports(pkg, specifier.replace('svelte', '.'), { + browser: true + })[0]; + + return new URL(subpath, LOCAL_PKG_URL).href; +} + +export function parse_npm_url(href: string) { + const match = /^npm:\/\/\$\/((?:@[^/]+\/)?[^/@]+)(?:@([^/]+))?(\/.+)?$/.exec(href); + + if (!match) { + throw new Error(`${href} is not a valid npm URL`); + } + + return { + name: match[1], + version: match[2], + subpath: match[3] + }; +} From 62e53a69ad8e623059a91f63c9128afe2da45885 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 2 Apr 2025 09:17:48 -0400 Subject: [PATCH 19/52] lint --- packages/repl/src/lib/workers/bundler/npm.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/repl/src/lib/workers/bundler/npm.ts b/packages/repl/src/lib/workers/bundler/npm.ts index 5ea59787b8..d52e4bee66 100644 --- a/packages/repl/src/lib/workers/bundler/npm.ts +++ b/packages/repl/src/lib/workers/bundler/npm.ts @@ -156,7 +156,7 @@ export async function resolve_local(specifier: string) { const subpath = resolve.exports(pkg, specifier.replace('svelte', '.'), { browser: true - })[0]; + })[0] as string; return new URL(subpath, LOCAL_PKG_URL).href; } From de3c9eb18096a8ffb6ba1836f8ab34877295db8c Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 2 Apr 2025 09:20:54 -0400 Subject: [PATCH 20/52] gah shut up typescript --- packages/repl/src/lib/workers/bundler/npm.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/repl/src/lib/workers/bundler/npm.ts b/packages/repl/src/lib/workers/bundler/npm.ts index d52e4bee66..c45f17510a 100644 --- a/packages/repl/src/lib/workers/bundler/npm.ts +++ b/packages/repl/src/lib/workers/bundler/npm.ts @@ -156,7 +156,7 @@ export async function resolve_local(specifier: string) { const subpath = resolve.exports(pkg, specifier.replace('svelte', '.'), { browser: true - })[0] as string; + })![0] as string; return new URL(subpath, LOCAL_PKG_URL).href; } From 3585435caf9d794c9c7d1b4c14e4cb6cdac12195 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 2 Apr 2025 09:41:48 -0400 Subject: [PATCH 21/52] remove unused stuff --- packages/repl/src/lib/Bundler.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/packages/repl/src/lib/Bundler.ts b/packages/repl/src/lib/Bundler.ts index 7c4884c5a0..0c9754c1f9 100644 --- a/packages/repl/src/lib/Bundler.ts +++ b/packages/repl/src/lib/Bundler.ts @@ -7,7 +7,6 @@ const workers = new Map(); let uid = 1; export default class Bundler { - svelte_version: string; worker: Worker; handlers: Map void>; @@ -20,8 +19,6 @@ export default class Bundler { onstatus: (val: string | null) => void; onerror?: (message: string) => void; }) { - this.svelte_version = svelte_version; - if (!workers.has(svelte_version)) { const worker = new Worker(new URL('./workers/bundler/index', import.meta.url), { type: 'module' @@ -70,10 +67,4 @@ export default class Bundler { uid += 1; }); } - - destroy() { - // TODO this is assymetrical and probably wrong? - this.worker.terminate(); - workers.delete(this.svelte_version); - } } From 6ed3f826e898ceded10cc6d039fc1c1b9fe4c8b0 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 2 Apr 2025 09:45:09 -0400 Subject: [PATCH 22/52] tidy up --- packages/repl/src/lib/Bundler.ts | 43 +++++++++++++++----------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/packages/repl/src/lib/Bundler.ts b/packages/repl/src/lib/Bundler.ts index 0c9754c1f9..3c334e0f21 100644 --- a/packages/repl/src/lib/Bundler.ts +++ b/packages/repl/src/lib/Bundler.ts @@ -7,8 +7,8 @@ const workers = new Map(); let uid = 1; export default class Bundler { - worker: Worker; - handlers: Map void>; + #worker: Worker; + #handlers = new Map void>(); constructor({ svelte_version, @@ -28,36 +28,33 @@ export default class Bundler { workers.set(svelte_version, worker); } - this.worker = workers.get(svelte_version); + this.#worker = workers.get(svelte_version); - this.handlers = new Map(); + this.#worker.addEventListener('message', (event: MessageEvent) => { + const handler = this.#handlers.get(event.data.uid); + if (!handler) return; // meant for different bundler with same worker - this.worker.addEventListener('message', (event: MessageEvent) => { - const handler = this.handlers.get(event.data.uid); - - if (handler) { - // if no handler, was meant for a different REPL - if (event.data.type === 'status') { - onstatus(event.data.message); - return; - } - - if (event.data.type === 'error') { - onerror?.(event.data.message); - return; - } + if (event.data.type === 'status') { + onstatus(event.data.message); + return; + } - onstatus(null); - handler(event.data); - this.handlers.delete(event.data.uid); + if (event.data.type === 'error') { + onerror?.(event.data.message); + return; } + + onstatus(null); + handler(event.data); + this.#handlers.delete(event.data.uid); }); } bundle(files: File[], options: { tailwind?: boolean }): Promise { return new Promise((fulfil) => { - this.handlers.set(uid, fulfil); - this.worker.postMessage({ + this.#handlers.set(uid, fulfil); + + this.#worker.postMessage({ uid, type: 'bundle', files, From dbeb383eb6f85c12a0eb4c059ea9c9ee1f070b97 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 2 Apr 2025 10:00:06 -0400 Subject: [PATCH 23/52] simplify some stuff --- .../(authed)/playground/[id]/+page.svelte | 27 +++++------------ packages/repl/src/lib/Bundler.ts | 30 +++++++++---------- packages/repl/src/lib/Repl.svelte | 3 ++ .../repl/src/lib/workers/bundler/index.ts | 10 +++++-- packages/repl/src/lib/workers/workers.d.ts | 2 +- 5 files changed, 35 insertions(+), 37 deletions(-) diff --git a/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte b/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte index 9cbb88eaad..6dd1ae26af 100644 --- a/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte +++ b/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte @@ -23,30 +23,11 @@ // svelte-ignore non_reactive_update let version = page.url.searchParams.get('version') || 'latest'; - let is_pr_or_commit_version = /^(pr|commit|branch)-(.+)/.test(version); // Hashed URLs are less safe (we can't delete malicious REPLs), therefore // don't allow links to escape the sandbox restrictions const can_escape = browser && !page.url.hash; - if (version !== 'local' && !is_pr_or_commit_version) { - $effect(() => { - fetch(`https://cdn.jsdelivr.net/npm/svelte@${version}/package.json`) - .then((r) => r.json()) - .then((pkg) => { - if (pkg.version !== version) { - version = pkg.version; - - let url = `/playground/${data.gist.id}?version=${version}`; - if (location.hash) { - url += location.hash; - } - replaceState(url, {}); - } - }); - }); - } - afterNavigate(() => { name = data.gist.name; set_files(); @@ -244,6 +225,14 @@ {onchange} {download} previewTheme={theme.current} + onversion={(v) => { + if (version === (version = v)) return; + + const url = new URL(location.href); + url.searchParams.set('version', v); + + replaceState(url, {}); + }} /> {/if} diff --git a/packages/repl/src/lib/Bundler.ts b/packages/repl/src/lib/Bundler.ts index 3c334e0f21..648cd2b136 100644 --- a/packages/repl/src/lib/Bundler.ts +++ b/packages/repl/src/lib/Bundler.ts @@ -2,8 +2,6 @@ import type { BundleResult } from './workers/bundler'; import type { BundleMessageData } from './workers/workers'; import type { File } from 'editor'; -const workers = new Map(); - let uid = 1; export default class Bundler { @@ -13,40 +11,42 @@ export default class Bundler { constructor({ svelte_version, onstatus, + onversion, onerror }: { svelte_version: string; onstatus: (val: string | null) => void; + onversion?: (version: string) => void; onerror?: (message: string) => void; }) { - if (!workers.has(svelte_version)) { - const worker = new Worker(new URL('./workers/bundler/index', import.meta.url), { - type: 'module' - }); - - worker.postMessage({ type: 'init', svelte_version }); - workers.set(svelte_version, worker); - } + this.#worker = new Worker(new URL('./workers/bundler/index', import.meta.url), { + type: 'module' + }); - this.#worker = workers.get(svelte_version); + this.#worker.postMessage({ type: 'init', svelte_version }); this.#worker.addEventListener('message', (event: MessageEvent) => { - const handler = this.#handlers.get(event.data.uid); - if (!handler) return; // meant for different bundler with same worker - if (event.data.type === 'status') { onstatus(event.data.message); return; } + if (event.data.type === 'version') { + onversion?.(event.data.message); + return; + } + if (event.data.type === 'error') { onerror?.(event.data.message); return; } onstatus(null); - handler(event.data); + + const handler = this.#handlers.get(event.data.uid); this.#handlers.delete(event.data.uid); + + handler(event.data); }); } diff --git a/packages/repl/src/lib/Repl.svelte b/packages/repl/src/lib/Repl.svelte index 6b98bfeae6..b019b63dcf 100644 --- a/packages/repl/src/lib/Repl.svelte +++ b/packages/repl/src/lib/Repl.svelte @@ -21,6 +21,7 @@ injectedJS?: string; injectedCSS?: string; previewTheme?: 'light' | 'dark'; + onversion?: (version: string) => void; onchange?: () => void; download?: () => void; } @@ -36,6 +37,7 @@ injectedJS = '', injectedCSS = '', previewTheme = 'light', + onversion, onchange = () => {}, download }: Props = $props(); @@ -121,6 +123,7 @@ const bundler = BROWSER ? new Bundler({ svelte_version: svelteVersion, + onversion, onstatus: (message) => { if (message) { // show bundler status, but only after time has elapsed, to diff --git a/packages/repl/src/lib/workers/bundler/index.ts b/packages/repl/src/lib/workers/bundler/index.ts index f4ee54aeb6..1c48dceb3d 100644 --- a/packages/repl/src/lib/workers/bundler/index.ts +++ b/packages/repl/src/lib/workers/bundler/index.ts @@ -39,10 +39,16 @@ let inited = Promise.withResolvers(); let can_use_experimental_async = false; -async function init(v: string) { +async function init(v: string, uid: number) { svelte_version = await resolve_version('svelte', v); console.log(`Using Svelte compiler version ${svelte_version}`); + self.postMessage({ + type: 'version', + uid, + message: svelte_version + }); + if (svelte_version === 'local') { await import(`${location.origin}/svelte/compiler/index.js`); } else { @@ -79,7 +85,7 @@ async function init(v: string) { self.addEventListener('message', async (event: MessageEvent) => { switch (event.data.type) { case 'init': { - init(event.data.svelte_version).then(inited.resolve, inited.reject); + init(event.data.svelte_version, event.data.uid).then(inited.resolve, inited.reject); break; } diff --git a/packages/repl/src/lib/workers/workers.d.ts b/packages/repl/src/lib/workers/workers.d.ts index d6fe0489a5..b81dd9527e 100644 --- a/packages/repl/src/lib/workers/workers.d.ts +++ b/packages/repl/src/lib/workers/workers.d.ts @@ -54,7 +54,7 @@ export interface BundleOptions { export type BundleMessageData = { uid: number; - type: 'init' | 'bundle' | 'status' | 'error'; + type: 'init' | 'bundle' | 'status' | 'error' | 'version'; message: string; svelte_version: string; files: File[]; From 994b068dd6c5233adfb01bfa1a1013c167183d10 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 2 Apr 2025 10:05:46 -0400 Subject: [PATCH 24/52] unused --- .../svelte.dev/src/lib/tutorial/adapters/rollup/index.svelte.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/svelte.dev/src/lib/tutorial/adapters/rollup/index.svelte.ts b/apps/svelte.dev/src/lib/tutorial/adapters/rollup/index.svelte.ts index f243cea92c..52ba8f02c2 100644 --- a/apps/svelte.dev/src/lib/tutorial/adapters/rollup/index.svelte.ts +++ b/apps/svelte.dev/src/lib/tutorial/adapters/rollup/index.svelte.ts @@ -16,8 +16,6 @@ export const state = new (class RollupState { * @returns {Promise} */ export async function create(): Promise { - bundler?.destroy(); - state.progress = { value: 0, text: 'loading files' }; let done = false; From 577f6828178eea6fb09be664b04bb902920bc63e Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 2 Apr 2025 10:47:51 -0400 Subject: [PATCH 25/52] only create tutorial bundler once --- .../svelte.dev/src/lib/tutorial/adapters/rollup/index.svelte.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/svelte.dev/src/lib/tutorial/adapters/rollup/index.svelte.ts b/apps/svelte.dev/src/lib/tutorial/adapters/rollup/index.svelte.ts index 52ba8f02c2..a3196b91ab 100644 --- a/apps/svelte.dev/src/lib/tutorial/adapters/rollup/index.svelte.ts +++ b/apps/svelte.dev/src/lib/tutorial/adapters/rollup/index.svelte.ts @@ -20,7 +20,7 @@ export async function create(): Promise { let done = false; - bundler = new Bundler({ + bundler ??= new Bundler({ svelte_version: 'latest', onstatus(val) { if (!done && val === null) { From 3d2e0181e8811a14bcfbc2267b1742e9c940654e Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 2 Apr 2025 11:11:09 -0400 Subject: [PATCH 26/52] lint --- packages/repl/src/lib/Bundler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/repl/src/lib/Bundler.ts b/packages/repl/src/lib/Bundler.ts index 648cd2b136..541508f546 100644 --- a/packages/repl/src/lib/Bundler.ts +++ b/packages/repl/src/lib/Bundler.ts @@ -43,7 +43,7 @@ export default class Bundler { onstatus(null); - const handler = this.#handlers.get(event.data.uid); + const handler = this.#handlers.get(event.data.uid)!; this.#handlers.delete(event.data.uid); handler(event.data); From a8b2a6a61aa1e5686f02ed64a546791769dcd8b6 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 2 Apr 2025 11:12:40 -0400 Subject: [PATCH 27/52] tidy up --- packages/repl/src/lib/Bundler.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/repl/src/lib/Bundler.ts b/packages/repl/src/lib/Bundler.ts index 541508f546..01eed1e292 100644 --- a/packages/repl/src/lib/Bundler.ts +++ b/packages/repl/src/lib/Bundler.ts @@ -23,9 +23,7 @@ export default class Bundler { type: 'module' }); - this.#worker.postMessage({ type: 'init', svelte_version }); - - this.#worker.addEventListener('message', (event: MessageEvent) => { + this.#worker.onmessage = (event: MessageEvent) => { if (event.data.type === 'status') { onstatus(event.data.message); return; @@ -47,7 +45,9 @@ export default class Bundler { this.#handlers.delete(event.data.uid); handler(event.data); - }); + }; + + this.#worker.postMessage({ type: 'init', svelte_version }); } bundle(files: File[], options: { tailwind?: boolean }): Promise { From e60a89091145fc512c103e06828708b13b0714af Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 2 Apr 2025 11:19:28 -0400 Subject: [PATCH 28/52] unused --- packages/repl/src/lib/workers/bundler/index.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/repl/src/lib/workers/bundler/index.ts b/packages/repl/src/lib/workers/bundler/index.ts index 1c48dceb3d..30bf9ad109 100644 --- a/packages/repl/src/lib/workers/bundler/index.ts +++ b/packages/repl/src/lib/workers/bundler/index.ts @@ -78,8 +78,6 @@ async function init(v: string, uid: number) { } catch (e) { // do nothing } - - return svelte; } self.addEventListener('message', async (event: MessageEvent) => { From a227036002f3079ccd78e18964d1be97d2000731 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 2 Apr 2025 11:38:31 -0400 Subject: [PATCH 29/52] move packages/editor into packages/repl, where it belongs --- .../tutorial/adapters/rollup/index.svelte.ts | 2 +- .../adapters/webcontainer/index.svelte.ts | 2 +- apps/svelte.dev/src/lib/tutorial/index.d.ts | 2 +- .../(authed)/playground/[id]/+page.svelte | 4 +- .../playground/[id]/AppControls.svelte | 5 +- .../playground/[id]/embed/+page.svelte | 4 +- .../routes/tutorial/[...slug]/+page.svelte | 4 +- .../routes/tutorial/[...slug]/Controls.svelte | 2 +- .../routes/tutorial/[...slug]/Output.svelte | 2 +- .../tutorial/[...slug]/adapter.svelte.ts | 2 +- .../tutorial/[...slug]/filetree/File.svelte | 2 +- .../[...slug]/filetree/Filetree.svelte | 2 +- .../tutorial/[...slug]/filetree/Folder.svelte | 2 +- .../routes/tutorial/[...slug]/state.svelte.ts | 2 +- packages/editor/.gitignore | 22 ------ packages/editor/.npmrc | 1 - packages/editor/.prettierignore | 4 - packages/editor/.prettierrc | 8 -- packages/editor/README.md | 58 --------------- packages/editor/package.json | 69 ------------------ packages/editor/src/app.d.ts | 13 ---- packages/editor/src/app.html | 12 --- packages/editor/src/lib/index.ts | 2 - packages/editor/src/routes/+page.svelte | 3 - packages/editor/static/favicon.png | Bin 1571 -> 0 bytes packages/editor/svelte.config.js | 18 ----- packages/editor/tsconfig.json | 15 ---- packages/editor/vite.config.ts | 6 -- packages/repl/package.json | 12 ++- packages/repl/src/lib/Bundler.ts | 2 +- .../index.ts => repl/src/lib/Compiler.ts} | 4 +- .../lib => repl/src/lib/Editor}/Editor.svelte | 2 +- .../src/lib/Editor}/close-dark.svg | 0 .../src/lib/Editor}/close-light.svg | 0 .../src/lib/Editor}/codemirror.css | 0 .../src/lib/Input/ComponentSelector.svelte | 2 +- packages/repl/src/lib/Output/AstView.svelte | 2 +- .../src/lib/Output/CompilerOptions.svelte | 2 +- packages/repl/src/lib/Output/Output.svelte | 5 +- packages/repl/src/lib/Repl.svelte | 3 +- .../src/lib/Workspace.svelte.ts | 2 +- packages/repl/src/lib/index.ts | 2 - packages/{editor => repl}/src/lib/theme.ts | 0 packages/repl/src/lib/types.d.ts | 2 +- .../repl/src/lib/workers/bundler/index.ts | 4 +- .../src/lib/workers/compiler/index.ts} | 2 +- packages/repl/src/lib/workers/workers.d.ts | 2 +- pnpm-lock.yaml | 6 ++ 48 files changed, 52 insertions(+), 270 deletions(-) delete mode 100644 packages/editor/.gitignore delete mode 100644 packages/editor/.npmrc delete mode 100644 packages/editor/.prettierignore delete mode 100644 packages/editor/.prettierrc delete mode 100644 packages/editor/README.md delete mode 100644 packages/editor/package.json delete mode 100644 packages/editor/src/app.d.ts delete mode 100644 packages/editor/src/app.html delete mode 100644 packages/editor/src/lib/index.ts delete mode 100644 packages/editor/src/routes/+page.svelte delete mode 100644 packages/editor/static/favicon.png delete mode 100644 packages/editor/svelte.config.js delete mode 100644 packages/editor/tsconfig.json delete mode 100644 packages/editor/vite.config.ts rename packages/{editor/src/lib/compile-worker/index.ts => repl/src/lib/Compiler.ts} (90%) rename packages/{editor/src/lib => repl/src/lib/Editor}/Editor.svelte (97%) rename packages/{editor/src/lib => repl/src/lib/Editor}/close-dark.svg (100%) rename packages/{editor/src/lib => repl/src/lib/Editor}/close-light.svg (100%) rename packages/{editor/src/lib => repl/src/lib/Editor}/codemirror.css (100%) rename packages/{editor => repl}/src/lib/Workspace.svelte.ts (99%) delete mode 100644 packages/repl/src/lib/index.ts rename packages/{editor => repl}/src/lib/theme.ts (100%) rename packages/{editor/src/lib/compile-worker/worker.ts => repl/src/lib/workers/compiler/index.ts} (98%) diff --git a/apps/svelte.dev/src/lib/tutorial/adapters/rollup/index.svelte.ts b/apps/svelte.dev/src/lib/tutorial/adapters/rollup/index.svelte.ts index a3196b91ab..98b12f144e 100644 --- a/apps/svelte.dev/src/lib/tutorial/adapters/rollup/index.svelte.ts +++ b/apps/svelte.dev/src/lib/tutorial/adapters/rollup/index.svelte.ts @@ -2,7 +2,7 @@ import Bundler from '@sveltejs/repl/bundler'; // @ts-ignore package exports don't have types import * as yootils from 'yootils'; import type { Adapter } from '$lib/tutorial'; -import type { File, Item } from 'editor'; +import type { File, Item } from '@sveltejs/repl/workspace'; /** Rollup bundler singleton */ let bundler: Bundler; diff --git a/apps/svelte.dev/src/lib/tutorial/adapters/webcontainer/index.svelte.ts b/apps/svelte.dev/src/lib/tutorial/adapters/webcontainer/index.svelte.ts index 6580c581f0..7682697847 100644 --- a/apps/svelte.dev/src/lib/tutorial/adapters/webcontainer/index.svelte.ts +++ b/apps/svelte.dev/src/lib/tutorial/adapters/webcontainer/index.svelte.ts @@ -7,7 +7,7 @@ import { get_depth } from '../../../utils/path.js'; import { escape_html } from '../../../utils/escape.js'; import { ready } from '../common/index.js'; import type { Adapter } from '$lib/tutorial'; -import type { Item, File } from 'editor'; +import type { Item, File } from '@sveltejs/repl/workspace'; const converter = new AnsiToHtml({ fg: 'var(--sk-fg-3)' diff --git a/apps/svelte.dev/src/lib/tutorial/index.d.ts b/apps/svelte.dev/src/lib/tutorial/index.d.ts index efc4f9a43c..487d7c9c2c 100644 --- a/apps/svelte.dev/src/lib/tutorial/index.d.ts +++ b/apps/svelte.dev/src/lib/tutorial/index.d.ts @@ -1,5 +1,5 @@ import type { Writable } from 'svelte/store'; -import type { File, Directory, Item } from 'editor'; +import type { File, Directory, Item } from '@sveltejs/repl/workspace'; export interface Adapter { /** Returns `false` if the reset was in such a way that a reload of the iframe isn't needed */ diff --git a/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte b/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte index 6dd1ae26af..06a6ab6965 100644 --- a/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte +++ b/apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte @@ -4,13 +4,13 @@ import { browser } from '$app/environment'; import { afterNavigate, goto, replaceState } from '$app/navigation'; import type { Gist } from '$lib/db/types'; - import { Repl } from '@sveltejs/repl'; + import Repl from '@sveltejs/repl'; import { theme } from '@sveltejs/site-kit/state'; import { mapbox_setup } from '../../../../config.js'; import AppControls from './AppControls.svelte'; import { compress_and_encode_text, decode_and_decompress_text } from './gzip.js'; import { page } from '$app/state'; - import type { File } from 'editor'; + import type { File } from '@sveltejs/repl/workspace'; let { data } = $props(); diff --git a/apps/svelte.dev/src/routes/(authed)/playground/[id]/AppControls.svelte b/apps/svelte.dev/src/routes/(authed)/playground/[id]/AppControls.svelte index 2e3af6c7a7..cafa92de64 100644 --- a/apps/svelte.dev/src/routes/(authed)/playground/[id]/AppControls.svelte +++ b/apps/svelte.dev/src/routes/(authed)/playground/[id]/AppControls.svelte @@ -7,10 +7,9 @@ import type { Gist, User } from '$lib/db/types'; import { browser } from '$app/environment'; import ModalDropdown from '$lib/components/ModalDropdown.svelte'; - import { untrack } from 'svelte'; import SecondaryNav from '$lib/components/SecondaryNav.svelte'; - import type { File } from 'editor'; - import type { Repl } from '@sveltejs/repl'; + import type { File } from '@sveltejs/repl/workspace'; + import type Repl from '@sveltejs/repl'; interface Props { examples: Array<{ title: string; examples: any[] }>; diff --git a/apps/svelte.dev/src/routes/(authed)/playground/[id]/embed/+page.svelte b/apps/svelte.dev/src/routes/(authed)/playground/[id]/embed/+page.svelte index acf9a88a70..ff944dee82 100644 --- a/apps/svelte.dev/src/routes/(authed)/playground/[id]/embed/+page.svelte +++ b/apps/svelte.dev/src/routes/(authed)/playground/[id]/embed/+page.svelte @@ -2,11 +2,11 @@ import { browser } from '$app/environment'; import { afterNavigate, replaceState } from '$app/navigation'; import { theme } from '@sveltejs/site-kit/state'; - import { Repl } from '@sveltejs/repl'; + import Repl from '@sveltejs/repl'; import { mapbox_setup } from '../../../../../config.js'; import { page } from '$app/state'; import { decode_and_decompress_text } from '../gzip.js'; - import type { File } from 'editor'; + import type { File } from '@sveltejs/repl/workspace'; let { data } = $props(); diff --git a/apps/svelte.dev/src/routes/tutorial/[...slug]/+page.svelte b/apps/svelte.dev/src/routes/tutorial/[...slug]/+page.svelte index d7cbda89aa..e919c4b10c 100644 --- a/apps/svelte.dev/src/routes/tutorial/[...slug]/+page.svelte +++ b/apps/svelte.dev/src/routes/tutorial/[...slug]/+page.svelte @@ -2,7 +2,7 @@ import { afterNavigate, beforeNavigate } from '$app/navigation'; import { SplitPane } from '@rich_harris/svelte-split-pane'; import * as adapter from './adapter.svelte'; - import { Editor, Workspace } from 'editor'; + import { Workspace, type Item } from '@sveltejs/repl/workspace'; import ContextMenu from './filetree/ContextMenu.svelte'; import Filetree from './filetree/Filetree.svelte'; import ImageViewer from './ImageViewer.svelte'; @@ -14,7 +14,7 @@ import OutputRollup from './OutputRollup.svelte'; import { page } from '$app/state'; import Controls from './Controls.svelte'; - import type { Item } from 'editor'; + import Editor from '@sveltejs/repl/editor'; import type { Snapshot } from './$types.js'; interface Props { diff --git a/apps/svelte.dev/src/routes/tutorial/[...slug]/Controls.svelte b/apps/svelte.dev/src/routes/tutorial/[...slug]/Controls.svelte index 003db02d6e..a825b1d990 100644 --- a/apps/svelte.dev/src/routes/tutorial/[...slug]/Controls.svelte +++ b/apps/svelte.dev/src/routes/tutorial/[...slug]/Controls.svelte @@ -4,7 +4,7 @@ import ModalDropdown from '$lib/components/ModalDropdown.svelte'; import type { Exercise, PartStub } from '$lib/tutorial'; import { Checkbox, Icon, Toolbox } from '@sveltejs/site-kit/components'; - import type { Workspace } from 'editor'; + import type { Workspace } from '@sveltejs/repl/workspace'; interface Props { index: PartStub[]; diff --git a/apps/svelte.dev/src/routes/tutorial/[...slug]/Output.svelte b/apps/svelte.dev/src/routes/tutorial/[...slug]/Output.svelte index f9fccd8e60..72a9bf8c2f 100644 --- a/apps/svelte.dev/src/routes/tutorial/[...slug]/Output.svelte +++ b/apps/svelte.dev/src/routes/tutorial/[...slug]/Output.svelte @@ -11,7 +11,7 @@ import Loading from './Loading.svelte'; import { adapter_state, subscribe, reset } from './adapter.svelte'; import type { Exercise } from '$lib/tutorial'; - import type { Workspace } from 'editor'; + import type { Workspace } from '@sveltejs/repl/workspace'; interface Props { exercise: Exercise; diff --git a/apps/svelte.dev/src/routes/tutorial/[...slug]/adapter.svelte.ts b/apps/svelte.dev/src/routes/tutorial/[...slug]/adapter.svelte.ts index 350f8c039e..26e67610ae 100644 --- a/apps/svelte.dev/src/routes/tutorial/[...slug]/adapter.svelte.ts +++ b/apps/svelte.dev/src/routes/tutorial/[...slug]/adapter.svelte.ts @@ -3,7 +3,7 @@ import { page } from '$app/stores'; import type { state as WCState } from '$lib/tutorial/adapters/webcontainer/index.svelte'; import type { state as RollupState } from '$lib/tutorial/adapters/rollup/index.svelte'; import type { Adapter } from '$lib/tutorial'; -import type { File, Item } from 'editor'; +import type { File, Item } from '@sveltejs/repl/workspace'; import { needs_webcontainers } from './shared'; let initial_load = true; diff --git a/apps/svelte.dev/src/routes/tutorial/[...slug]/filetree/File.svelte b/apps/svelte.dev/src/routes/tutorial/[...slug]/filetree/File.svelte index 9bb3067204..5da9f62bc1 100644 --- a/apps/svelte.dev/src/routes/tutorial/[...slug]/filetree/File.svelte +++ b/apps/svelte.dev/src/routes/tutorial/[...slug]/filetree/File.svelte @@ -4,7 +4,7 @@ import file_icon from '$lib/icons/file.svg'; import { solution } from '../state.svelte'; import type { MenuItem } from '$lib/tutorial'; - import type { File } from 'editor'; + import type { File } from '@sveltejs/repl/workspace'; interface Props { file: File; diff --git a/apps/svelte.dev/src/routes/tutorial/[...slug]/filetree/Filetree.svelte b/apps/svelte.dev/src/routes/tutorial/[...slug]/filetree/Filetree.svelte index a82ff49a99..d4cfe306e9 100644 --- a/apps/svelte.dev/src/routes/tutorial/[...slug]/filetree/Filetree.svelte +++ b/apps/svelte.dev/src/routes/tutorial/[...slug]/filetree/Filetree.svelte @@ -6,7 +6,7 @@ import { solution } from '../state.svelte'; import { afterNavigate } from '$app/navigation'; import type { Exercise } from '$lib/tutorial'; - import type { Workspace, Item } from 'editor'; + import type { Workspace, Item } from '@sveltejs/repl/workspace'; interface Props { exercise: Exercise; diff --git a/apps/svelte.dev/src/routes/tutorial/[...slug]/filetree/Folder.svelte b/apps/svelte.dev/src/routes/tutorial/[...slug]/filetree/Folder.svelte index 9495998d21..c16bd233a5 100644 --- a/apps/svelte.dev/src/routes/tutorial/[...slug]/filetree/Folder.svelte +++ b/apps/svelte.dev/src/routes/tutorial/[...slug]/filetree/Folder.svelte @@ -8,7 +8,7 @@ import folder_open from '$lib/icons/folder-open.svg'; import { solution } from '../state.svelte'; import type { MenuItem } from '$lib/tutorial'; - import type { Directory, File as IFile, Item as IItem } from 'editor'; + import type { Directory, File as IFile, Item as IItem } from '@sveltejs/repl/workspace'; interface Props { directory: Directory; diff --git a/apps/svelte.dev/src/routes/tutorial/[...slug]/state.svelte.ts b/apps/svelte.dev/src/routes/tutorial/[...slug]/state.svelte.ts index cd0ae03614..c2eaf7f1b7 100644 --- a/apps/svelte.dev/src/routes/tutorial/[...slug]/state.svelte.ts +++ b/apps/svelte.dev/src/routes/tutorial/[...slug]/state.svelte.ts @@ -1,4 +1,4 @@ import { writable } from 'svelte/store'; -import type { Item } from 'editor'; +import type { Item } from '@sveltejs/repl/workspace'; export const solution = writable({} as Record); diff --git a/packages/editor/.gitignore b/packages/editor/.gitignore deleted file mode 100644 index 715b548f7b..0000000000 --- a/packages/editor/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -node_modules - -# Output -.output -.vercel -/.svelte-kit -/build -/dist - -# OS -.DS_Store -Thumbs.db - -# Env -.env -.env.* -!.env.example -!.env.test - -# Vite -vite.config.js.timestamp-* -vite.config.ts.timestamp-* diff --git a/packages/editor/.npmrc b/packages/editor/.npmrc deleted file mode 100644 index b6f27f1359..0000000000 --- a/packages/editor/.npmrc +++ /dev/null @@ -1 +0,0 @@ -engine-strict=true diff --git a/packages/editor/.prettierignore b/packages/editor/.prettierignore deleted file mode 100644 index ab78a95ddd..0000000000 --- a/packages/editor/.prettierignore +++ /dev/null @@ -1,4 +0,0 @@ -# Package Managers -package-lock.json -pnpm-lock.yaml -yarn.lock diff --git a/packages/editor/.prettierrc b/packages/editor/.prettierrc deleted file mode 100644 index 95730232b6..0000000000 --- a/packages/editor/.prettierrc +++ /dev/null @@ -1,8 +0,0 @@ -{ - "useTabs": true, - "singleQuote": true, - "trailingComma": "none", - "printWidth": 100, - "plugins": ["prettier-plugin-svelte"], - "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] -} diff --git a/packages/editor/README.md b/packages/editor/README.md deleted file mode 100644 index 69f4875945..0000000000 --- a/packages/editor/README.md +++ /dev/null @@ -1,58 +0,0 @@ -# create-svelte - -Everything you need to build a Svelte library, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte). - -Read more about creating a library [in the docs](https://kit.svelte.dev/docs/packaging). - -## Creating a project - -If you're seeing this, you've probably already done this step. Congrats! - -```bash -# create a new project in the current directory -npm create svelte@latest - -# create a new project in my-app -npm create svelte@latest my-app -``` - -## Developing - -Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: - -```bash -npm run dev - -# or start the server and open the app in a new browser tab -npm run dev -- --open -``` - -Everything inside `src/lib` is part of your library, everything inside `src/routes` can be used as a showcase or preview app. - -## Building - -To build your library: - -```bash -npm run package -``` - -To create a production version of your showcase app: - -```bash -npm run build -``` - -You can preview the production build with `npm run preview`. - -> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment. - -## Publishing - -Go into the `package.json` and give your package the desired name through the `"name"` option. Also consider adding a `"license"` field and point it to a `LICENSE` file which you can create from a template (one popular option is the [MIT license](https://opensource.org/license/mit/)). - -To publish your library to [npm](https://www.npmjs.com): - -```bash -npm publish -``` diff --git a/packages/editor/package.json b/packages/editor/package.json deleted file mode 100644 index 17651a37c3..0000000000 --- a/packages/editor/package.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "name": "editor", - "version": "0.0.1", - "private": true, - "scripts": { - "dev": "vite dev", - "build": "vite build && npm run package", - "preview": "vite preview", - "package": "svelte-kit sync && svelte-package && publint", - "prepublishOnly": "npm run package", - "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", - "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", - "lint": "prettier --check .", - "format": "prettier --write .", - "prepare": "svelte-kit sync" - }, - "exports": { - ".": { - "types": "./src/lib/index.ts", - "svelte": "./src/lib/index.ts" - } - }, - "sideEffects": [ - "**/*.css" - ], - "files": [ - "src", - "dist", - "!dist/**/*.test.*", - "!dist/**/*.spec.*" - ], - "peerDependencies": { - "svelte": "^5.0.0" - }, - "devDependencies": { - "@codemirror/autocomplete": "^6.9.0", - "@codemirror/commands": "^6.2.5", - "@codemirror/lang-css": "^6.2.1", - "@codemirror/lang-html": "^6.4.6", - "@codemirror/lang-javascript": "^6.2.1", - "@codemirror/language": "^6.10.3", - "@codemirror/lint": "^6.8.2", - "@codemirror/search": "^6.5.6", - "@codemirror/state": "^6.5.0", - "@codemirror/view": "^6.35.3", - "@replit/codemirror-lang-svelte": "^6.0.0", - "@replit/codemirror-vim": "^6.0.14", - "@sveltejs/adapter-auto": "^3.0.0", - "@sveltejs/kit": "^2.20.0", - "@sveltejs/package": "^2.0.0", - "@sveltejs/repl": "workspace:*", - "@sveltejs/site-kit": "workspace:*", - "@sveltejs/vite-plugin-svelte": "^4.0.0", - "codemirror": "^6.0.1", - "prettier": "^3.1.1", - "prettier-plugin-svelte": "^3.3.2", - "publint": "^0.2.12", - "svelte": "^5.23.0", - "svelte-check": "^4.1.1", - "typescript": "^5.0.0", - "vite": "^5.0.11" - }, - "type": "module", - "dependencies": { - "@lezer/highlight": "^1.2.1", - "esm-env": "^1.0.0", - "tarparser": "^0.0.4" - } -} diff --git a/packages/editor/src/app.d.ts b/packages/editor/src/app.d.ts deleted file mode 100644 index 743f07b2e5..0000000000 --- a/packages/editor/src/app.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -// See https://kit.svelte.dev/docs/types#app -// for information about these interfaces -declare global { - namespace App { - // interface Error {} - // interface Locals {} - // interface PageData {} - // interface PageState {} - // interface Platform {} - } -} - -export {}; diff --git a/packages/editor/src/app.html b/packages/editor/src/app.html deleted file mode 100644 index f22aeaad5e..0000000000 --- a/packages/editor/src/app.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - %sveltekit.head% - - -
%sveltekit.body%
- - diff --git a/packages/editor/src/lib/index.ts b/packages/editor/src/lib/index.ts deleted file mode 100644 index 962edd774b..0000000000 --- a/packages/editor/src/lib/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default as Editor } from './Editor.svelte'; -export * from './Workspace.svelte'; diff --git a/packages/editor/src/routes/+page.svelte b/packages/editor/src/routes/+page.svelte deleted file mode 100644 index 0a45b69f09..0000000000 --- a/packages/editor/src/routes/+page.svelte +++ /dev/null @@ -1,3 +0,0 @@ -

Welcome to your library project

-

Create your package using @sveltejs/package and preview/showcase your work with SvelteKit

-

Visit kit.svelte.dev to read the documentation

diff --git a/packages/editor/static/favicon.png b/packages/editor/static/favicon.png deleted file mode 100644 index 825b9e65af7c104cfb07089bb28659393b4f2097..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1571 zcmV+;2Hg3HP)Px)-AP12RCwC$UE6KzI1p6{F2N z1VK2vi|pOpn{~#djwYcWXTI_im_u^TJgMZ4JMOsSj!0ma>B?-(Hr@X&W@|R-$}W@Z zgj#$x=!~7LGqHW?IO8+*oE1MyDp!G=L0#^lUx?;!fXv@l^6SvTnf^ac{5OurzC#ZMYc20lI%HhX816AYVs1T3heS1*WaWH z%;x>)-J}YB5#CLzU@GBR6sXYrD>Vw(Fmt#|JP;+}<#6b63Ike{Fuo!?M{yEffez;| zp!PfsuaC)>h>-AdbnwN13g*1LowNjT5?+lFVd#9$!8Z9HA|$*6dQ8EHLu}U|obW6f z2%uGv?vr=KNq7YYa2Roj;|zooo<)lf=&2yxM@e`kM$CmCR#x>gI>I|*Ubr({5Y^rb zghxQU22N}F51}^yfDSt786oMTc!W&V;d?76)9KXX1 z+6Okem(d}YXmmOiZq$!IPk5t8nnS{%?+vDFz3BevmFNgpIod~R{>@#@5x9zJKEHLHv!gHeK~n)Ld!M8DB|Kfe%~123&Hz1Z(86nU7*G5chmyDe ziV7$pB7pJ=96hpxHv9rCR29%bLOXlKU<_13_M8x)6;P8E1Kz6G<&P?$P^%c!M5`2` zfY2zg;VK5~^>TJGQzc+33-n~gKt{{of8GzUkWmU110IgI0DLxRIM>0US|TsM=L|@F z0Bun8U!cRB7-2apz=y-7*UxOxz@Z0)@QM)9wSGki1AZ38ceG7Q72z5`i;i=J`ILzL z@iUO?SBBG-0cQuo+an4TsLy-g-x;8P4UVwk|D8{W@U1Zi z!M)+jqy@nQ$p?5tsHp-6J304Q={v-B>66$P0IDx&YT(`IcZ~bZfmn11#rXd7<5s}y zBi9eim&zQc0Dk|2>$bs0PnLmDfMP5lcXRY&cvJ=zKxI^f0%-d$tD!`LBf9^jMSYUA zI8U?CWdY@}cRq6{5~y+)#h1!*-HcGW@+gZ4B};0OnC~`xQOyH19z*TA!!BJ%9s0V3F?CAJ{hTd#*tf+ur-W9MOURF-@B77_-OshsY}6 zOXRY=5%C^*26z?l)1=$bz30!so5tfABdSYzO+H=CpV~aaUefmjvfZ3Ttu9W&W3Iu6 zROlh0MFA5h;my}8lB0tAV-Rvc2Zs_CCSJnx@d`**$idgy-iMob4dJWWw|21b4NB=LfsYp0Aeh{Ov)yztQi;eL4y5 zMi>8^SzKqk8~k?UiQK^^-5d8c%bV?$F8%X~czyiaKCI2=UH void>>(); @@ -8,7 +8,7 @@ let worker: Worker; let uid = 1; if (BROWSER) { - worker = new Worker(new URL('./worker', import.meta.url), { + worker = new Worker(new URL('./workers/compiler/index', import.meta.url), { type: 'module' }); diff --git a/packages/editor/src/lib/Editor.svelte b/packages/repl/src/lib/Editor/Editor.svelte similarity index 97% rename from packages/editor/src/lib/Editor.svelte rename to packages/repl/src/lib/Editor/Editor.svelte index a017f9e8c5..fbf981f20d 100644 --- a/packages/editor/src/lib/Editor.svelte +++ b/packages/repl/src/lib/Editor/Editor.svelte @@ -2,7 +2,7 @@ import { BROWSER } from 'esm-env'; import { setDiagnostics } from '@codemirror/lint'; import { EditorView } from '@codemirror/view'; - import { Workspace, type File } from './Workspace.svelte.js'; + import { Workspace, type File } from '../Workspace.svelte'; import './codemirror.css'; interface Props { diff --git a/packages/editor/src/lib/close-dark.svg b/packages/repl/src/lib/Editor/close-dark.svg similarity index 100% rename from packages/editor/src/lib/close-dark.svg rename to packages/repl/src/lib/Editor/close-dark.svg diff --git a/packages/editor/src/lib/close-light.svg b/packages/repl/src/lib/Editor/close-light.svg similarity index 100% rename from packages/editor/src/lib/close-light.svg rename to packages/repl/src/lib/Editor/close-light.svg diff --git a/packages/editor/src/lib/codemirror.css b/packages/repl/src/lib/Editor/codemirror.css similarity index 100% rename from packages/editor/src/lib/codemirror.css rename to packages/repl/src/lib/Editor/codemirror.css diff --git a/packages/repl/src/lib/Input/ComponentSelector.svelte b/packages/repl/src/lib/Input/ComponentSelector.svelte index b7fb95b3fa..f6bb459244 100644 --- a/packages/repl/src/lib/Input/ComponentSelector.svelte +++ b/packages/repl/src/lib/Input/ComponentSelector.svelte @@ -1,6 +1,6 @@ diff --git a/packages/repl/src/lib/Output/Output.svelte b/packages/repl/src/lib/Output/Output.svelte index 008511c753..76857a522f 100644 --- a/packages/repl/src/lib/Output/Output.svelte +++ b/packages/repl/src/lib/Output/Output.svelte @@ -5,8 +5,9 @@ import CompilerOptions from './CompilerOptions.svelte'; import PaneWithPanel from './PaneWithPanel.svelte'; import Viewer from './Viewer.svelte'; - import { Editor, Workspace, type File } from 'editor'; - import { tick, untrack } from 'svelte'; + import { Workspace, type File } from '../Workspace.svelte'; + import Editor from '../Editor/Editor.svelte'; + import { untrack } from 'svelte'; import { decode, type SourceMapSegment } from '@jridgewell/sourcemap-codec'; interface Props { diff --git a/packages/repl/src/lib/Repl.svelte b/packages/repl/src/lib/Repl.svelte index b019b63dcf..103bd5ff96 100644 --- a/packages/repl/src/lib/Repl.svelte +++ b/packages/repl/src/lib/Repl.svelte @@ -7,7 +7,8 @@ import ComponentSelector from './Input/ComponentSelector.svelte'; import Output from './Output/Output.svelte'; import { set_repl_context } from './context.js'; - import { Workspace, Editor, type File } from 'editor'; + import { Workspace, type File } from './Workspace.svelte.js'; + import Editor from './Editor/Editor.svelte'; import type { Bundle, ReplContext } from './types.js'; interface Props { diff --git a/packages/editor/src/lib/Workspace.svelte.ts b/packages/repl/src/lib/Workspace.svelte.ts similarity index 99% rename from packages/editor/src/lib/Workspace.svelte.ts rename to packages/repl/src/lib/Workspace.svelte.ts index a4ec178e02..14dfafa5ff 100644 --- a/packages/editor/src/lib/Workspace.svelte.ts +++ b/packages/repl/src/lib/Workspace.svelte.ts @@ -1,6 +1,6 @@ import type { CompileError, CompileResult } from 'svelte/compiler'; import { Compartment, EditorState, StateEffect, StateField } from '@codemirror/state'; -import { compile_file } from './compile-worker'; +import { compile_file } from './Compiler'; import { BROWSER } from 'esm-env'; import { basicSetup, EditorView } from 'codemirror'; import { javascript } from '@codemirror/lang-javascript'; diff --git a/packages/repl/src/lib/index.ts b/packages/repl/src/lib/index.ts deleted file mode 100644 index a730b23f10..0000000000 --- a/packages/repl/src/lib/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default as Repl } from './Repl.svelte'; -export type { File } from './types'; diff --git a/packages/editor/src/lib/theme.ts b/packages/repl/src/lib/theme.ts similarity index 100% rename from packages/editor/src/lib/theme.ts rename to packages/repl/src/lib/theme.ts diff --git a/packages/repl/src/lib/types.d.ts b/packages/repl/src/lib/types.d.ts index a46e9f0766..ebbc214e5c 100644 --- a/packages/repl/src/lib/types.d.ts +++ b/packages/repl/src/lib/types.d.ts @@ -2,7 +2,7 @@ import type { EditorState } from '@codemirror/state'; import { OutputChunk, RollupError } from '@rollup/browser'; import type { Readable, Writable } from 'svelte/store'; import type { CompileError } from 'svelte/compiler'; -import type { Workspace } from 'editor'; +import type { Workspace } from './Workspace.svelte'; export type Lang = 'js' | 'svelte' | 'json' | 'md' | 'css' | (string & Record); diff --git a/packages/repl/src/lib/workers/bundler/index.ts b/packages/repl/src/lib/workers/bundler/index.ts index 30bf9ad109..a3756c99c2 100644 --- a/packages/repl/src/lib/workers/bundler/index.ts +++ b/packages/repl/src/lib/workers/bundler/index.ts @@ -15,7 +15,7 @@ import type { Plugin, RollupCache, TransformResult } from '@rollup/browser'; import type { BundleMessageData, BundleOptions } from '../workers'; import type { Warning } from '../../types'; import type { CompileError, CompileResult } from 'svelte/compiler'; -import type { File } from 'editor'; +import type { File } from '../../Workspace.svelte'; import type { Node } from 'estree'; import { max } from './semver'; import { ENTRYPOINT, ESM_ENV, NPM, STYLES, VIRTUAL } from './constants'; @@ -35,7 +35,7 @@ self.window = self; let svelte_version: string; let current_id: number; -let inited = Promise.withResolvers(); +let inited = Promise.withResolvers(); let can_use_experimental_async = false; diff --git a/packages/editor/src/lib/compile-worker/worker.ts b/packages/repl/src/lib/workers/compiler/index.ts similarity index 98% rename from packages/editor/src/lib/compile-worker/worker.ts rename to packages/repl/src/lib/workers/compiler/index.ts index d5fd227096..5965038f8a 100644 --- a/packages/editor/src/lib/compile-worker/worker.ts +++ b/packages/repl/src/lib/workers/compiler/index.ts @@ -1,7 +1,7 @@ import '@sveltejs/site-kit/polyfills'; import { parseTar } from 'tarparser'; import type { CompileResult } from 'svelte/compiler'; -import type { ExposedCompilerOptions, File } from '../Workspace.svelte'; +import type { ExposedCompilerOptions, File } from '../../Workspace.svelte'; import type { FileDescription } from 'tarparser'; // hack for magic-string and Svelte 4 compiler diff --git a/packages/repl/src/lib/workers/workers.d.ts b/packages/repl/src/lib/workers/workers.d.ts index b81dd9527e..d4b27d21e2 100644 --- a/packages/repl/src/lib/workers/workers.d.ts +++ b/packages/repl/src/lib/workers/workers.d.ts @@ -1,5 +1,5 @@ import type { CompileError, CompileOptions, CompileResult, Warning } from 'svelte/compiler'; -import type { File } from 'editor'; +import type { File } from '../Workspace.svelte'; export type CompilerCommand = | { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 954338e930..4f9ef75b3d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -310,6 +310,9 @@ importers: '@codemirror/lang-css': specifier: ^6.2.1 version: 6.2.1(@codemirror/view@6.35.3) + '@codemirror/lang-html': + specifier: ^6.4.6 + version: 6.4.9 '@codemirror/lang-javascript': specifier: ^6.2.2 version: 6.2.2 @@ -355,6 +358,9 @@ importers: acorn: specifier: ^8.11.3 version: 8.14.0 + codemirror: + specifier: ^6.0.1 + version: 6.0.1(@lezer/common@1.2.2) editor: specifier: workspace:* version: link:../editor From 820c300fe4d7333fc6c24186140d203bdb817456 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 2 Apr 2025 12:07:46 -0400 Subject: [PATCH 30/52] lint --- .../src/routes/tutorial/[...slug]/ImageViewer.svelte | 2 +- .../src/routes/tutorial/[...slug]/OutputRollup.svelte | 4 ++-- .../src/routes/tutorial/[...slug]/filetree/context.js | 6 +++--- packages/repl/package.json | 8 +++++++- packages/repl/src/lib/Output/Viewer.svelte | 2 +- packages/repl/src/lib/Workspace.svelte.ts | 2 +- 6 files changed, 15 insertions(+), 9 deletions(-) diff --git a/apps/svelte.dev/src/routes/tutorial/[...slug]/ImageViewer.svelte b/apps/svelte.dev/src/routes/tutorial/[...slug]/ImageViewer.svelte index 8d69298a05..65c65c8a3f 100644 --- a/apps/svelte.dev/src/routes/tutorial/[...slug]/ImageViewer.svelte +++ b/apps/svelte.dev/src/routes/tutorial/[...slug]/ImageViewer.svelte @@ -1,5 +1,5 @@