diff --git a/.changeset/purple-impalas-deliver.md b/.changeset/purple-impalas-deliver.md new file mode 100644 index 000000000000..cf2a650a5a56 --- /dev/null +++ b/.changeset/purple-impalas-deliver.md @@ -0,0 +1,6 @@ +--- +'@sveltejs/kit': patch +'@sveltejs/snowpack-config': patch +--- + +Move kit runtime code, expose via \$app aliases diff --git a/packages/kit/.gitignore b/packages/kit/.gitignore index fc683b4725d6..b8137f2ebe2c 100644 --- a/packages/kit/.gitignore +++ b/packages/kit/.gitignore @@ -1,5 +1,5 @@ .DS_Store /node_modules /dist -/assets/client.* +/assets/runtime /client/**/*.d.ts diff --git a/packages/kit/assets/setup.js b/packages/kit/assets/setup.js deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/packages/kit/dummy/manifest.ts b/packages/kit/dummy/manifest.ts deleted file mode 100644 index 6982d3aa8663..000000000000 --- a/packages/kit/dummy/manifest.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const ErrorComponent = {}; - -export const components = []; - -export const routes = []; \ No newline at end of file diff --git a/packages/kit/dummy/root.ts b/packages/kit/dummy/root.ts deleted file mode 100644 index afc2e1000dac..000000000000 --- a/packages/kit/dummy/root.ts +++ /dev/null @@ -1,13 +0,0 @@ -export function preload(_page: any, _session: any) { - -} - -export default class root { - constructor(_opts: any) { - - } - - $set(_data: any) { - - } -} \ No newline at end of file diff --git a/packages/kit/rollup.config.js b/packages/kit/rollup.config.js index b75f870fc11d..d1eb435aa047 100644 --- a/packages/kit/rollup.config.js +++ b/packages/kit/rollup.config.js @@ -12,17 +12,21 @@ const external = [].concat( export default [ { - input: 'src/client/index.ts', + input: { + navigation: 'src/runtime/navigation/index.ts', + stores: 'src/runtime/stores/index.ts' + }, output: { - file: 'assets/client.js', + dir: 'assets/runtime', format: 'esm', sourcemap: true, paths: { - ROOT: './root.svelte', - MANIFEST: './manifest.js' + ROOT: '../generated/root.svelte', + MANIFEST: '../generated/manifest.js' } }, external: [ + 'svelte', 'svelte/store', 'ROOT', 'MANIFEST' diff --git a/packages/kit/src/api/build/index.ts b/packages/kit/src/api/build/index.ts index 6338ced6d603..d330bcaaa977 100644 --- a/packages/kit/src/api/build/index.ts +++ b/packages/kit/src/api/build/index.ts @@ -4,7 +4,7 @@ import child_process from 'child_process'; import { promisify } from 'util'; import colors from 'kleur'; import relative from 'require-relative'; -import { mkdirp } from '@sveltejs/app-utils'; +import { mkdirp } from '@sveltejs/app-utils/files'; import create_manifest_data from '../../core/create_manifest_data'; import { rollup, @@ -28,7 +28,7 @@ const ignorable_warnings = new Set(['EMPTY_BUNDLE', 'CIRCULAR_DEPENDENCY']); const onwarn = (warning, handler) => { // TODO would be nice to just eliminate the circular dependencies instead of // squelching these warnings (it happens when e.g. the root layout imports - // from /_app/main/client) + // from /_app/main/runtime/navigation) if (ignorable_warnings.has(warning.code)) return; handler(warning); }; @@ -64,6 +64,12 @@ export async function build(config: SvelteAppConfig) { copy_assets(); + const setup_file = `${unoptimized}/server/_app/setup/index.js`; + if (!fs.existsSync(setup_file)) { + mkdirp(path.dirname(setup_file)); + fs.writeFileSync(setup_file, ''); + } + await exec(`${snowpack_bin} build --out=${unoptimized}/server --ssr`); log.success('server'); await exec(`${snowpack_bin} build --out=${unoptimized}/client`); @@ -76,11 +82,8 @@ export async function build(config: SvelteAppConfig) { await exec(`rm -rf .svelte/build/optimized`); const server_input = { - root: `${unoptimized}/server/_app/main/root.js`, - setup: fs.existsSync(`${unoptimized}/server/_app/setup/index.js`) - ? `${unoptimized}/server/_app/setup/index.js` - : path.join(__dirname, '../assets/setup.js'), - // TODO session middleware etc + root: `${unoptimized}/server/_app/main/generated/root.js`, + setup: `${unoptimized}/server/_app/setup/index.js` }; [ @@ -91,9 +94,21 @@ export async function build(config: SvelteAppConfig) { server_input[`routes/${item.name}`] = `${unoptimized}/server${item.url.replace(/\.\w+$/, '.js')}`; }); + // https://github.com/snowpackjs/snowpack/discussions/1395 + const re = /(\.\.\/)+_app\/main\/runtime\//; + const work_around_alias_bug = type => ({ + name: 'work-around-alias-bug', + resolveId(imported) { + if (re.test(imported)) { + return path.resolve(`${unoptimized}/${type}/_app/main/runtime`, imported.replace(re, '')); + } + } + }); + const server_chunks = await rollup({ input: server_input, plugins: [ + work_around_alias_bug('server'), { name: 'remove-css', load(id) { @@ -123,13 +138,14 @@ export async function build(config: SvelteAppConfig) { log.success(`server`); - const entry = path.resolve(`${unoptimized}/client/_app/main/client.js`); + const entry = path.resolve(`${unoptimized}/client/_app/main/runtime/navigation.js`); const client_chunks = await rollup({ input: { entry }, plugins: [ + work_around_alias_bug('client'), { name: 'deproxy-css', async resolveId(importee, importer) { @@ -189,18 +205,18 @@ export async function build(config: SvelteAppConfig) { const chunk = bundle[key]; - if (!(chunk as OutputChunk).imports) { - console.log(chunk); - } + const imports = chunk && (chunk as OutputChunk).imports; - (chunk as OutputChunk).imports.forEach(key => { - if (key.endsWith('.css')) { - js.add(inject_styles); - css.add(key); - } else { - find_deps(key, js, css); - } - }); + if (imports) { + imports.forEach(key => { + if (key.endsWith('.css')) { + js.add(inject_styles); + css.add(key); + } else { + find_deps(key, js, css); + } + }); + } return { js, css }; }; diff --git a/packages/kit/src/api/dev/index.ts b/packages/kit/src/api/dev/index.ts index 18b4b5773686..ff0a2787610c 100644 --- a/packages/kit/src/api/dev/index.ts +++ b/packages/kit/src/api/dev/index.ts @@ -141,7 +141,7 @@ class Watcher extends EventEmitter { let root; try { - root = await load(`/_app/main/root.js`); + root = await load(`/_app/main/generated/root.js`); } catch (e) { res.statusCode = 500; @@ -163,7 +163,7 @@ class Watcher extends EventEmitter { template, manifest: this.manifest, client: { - entry: 'main/client.js', + entry: 'main/runtime/navigation.js', deps: {} }, files: 'build', diff --git a/packages/kit/src/api/utils.ts b/packages/kit/src/api/utils.ts index bd0053932b23..104f97c467a5 100644 --- a/packages/kit/src/api/utils.ts +++ b/packages/kit/src/api/utils.ts @@ -1,11 +1,6 @@ -import { copyFileSync } from 'fs'; import { resolve } from 'path'; -import { mkdirp } from '@sveltejs/app-utils/files'; +import { copy } from '@sveltejs/app-utils/files'; export function copy_assets() { - mkdirp('.svelte/main/components'); - - ['client.js', 'components/layout.svelte', 'components/error.svelte'].forEach(file => { - copyFileSync(resolve(__dirname, `../assets/${file}`), `.svelte/main/${file}`) - }); + copy(resolve(__dirname, `../assets`), '.svelte/main'); } \ No newline at end of file diff --git a/packages/kit/src/client/index.ts b/packages/kit/src/client/index.ts deleted file mode 100644 index e7ee6809ca32..000000000000 --- a/packages/kit/src/client/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { getContext } from 'svelte'; - -export const stores = () => getContext('__svelte__'); - -export { default as start } from './app'; -export { default as goto } from './goto/index'; -export { default as prefetch } from './prefetch/index'; -export { default as prefetchRoutes } from './prefetchRoutes/index'; diff --git a/packages/kit/src/client/router/find_anchor.ts b/packages/kit/src/client/router/find_anchor.ts deleted file mode 100644 index 95afc87cb3e1..000000000000 --- a/packages/kit/src/client/router/find_anchor.ts +++ /dev/null @@ -1,4 +0,0 @@ -export default function find_anchor(node: Node) { - while (node && node.nodeName.toUpperCase() !== 'A') node = node.parentNode; // SVG elements have a lowercase name - return node; -} diff --git a/packages/kit/src/core/create_app.ts b/packages/kit/src/core/create_app.ts index 35f5194d6e1a..3fd04da91b44 100644 --- a/packages/kit/src/core/create_app.ts +++ b/packages/kit/src/core/create_app.ts @@ -16,8 +16,8 @@ export function create_app({ const app = generate_app(manifest_data); - write_if_changed(`${output}/manifest.js`, client_manifest); - write_if_changed(`${output}/root.svelte`, app); + write_if_changed(`${output}/generated/manifest.js`, client_manifest); + write_if_changed(`${output}/generated/root.svelte`, app); } export function create_serviceworker_manifest({ manifest_data, output, client_files, static_files }: { diff --git a/packages/kit/src/client/goto/index.ts b/packages/kit/src/runtime/navigation/goto/index.ts similarity index 79% rename from packages/kit/src/client/goto/index.ts rename to packages/kit/src/runtime/navigation/goto/index.ts index ccbda1139851..87c120b10077 100644 --- a/packages/kit/src/client/goto/index.ts +++ b/packages/kit/src/runtime/navigation/goto/index.ts @@ -1,5 +1,5 @@ -import { cid, history, navigate, select_target } from '../router'; -import { get_base_uri } from '../baseuri_helper'; +import { cid, history, navigate, select_target } from '../internal'; +import { get_base_uri } from '../utils'; export default function goto( href: string, diff --git a/packages/kit/src/runtime/navigation/index.ts b/packages/kit/src/runtime/navigation/index.ts new file mode 100644 index 000000000000..be98c38176e2 --- /dev/null +++ b/packages/kit/src/runtime/navigation/index.ts @@ -0,0 +1,4 @@ +export { default as goto } from './goto'; +export { default as prefetch } from './prefetch'; +export { default as prefetchRoutes } from './prefetchRoutes'; +export { default as start } from './start'; \ No newline at end of file diff --git a/packages/kit/src/client/router/index.ts b/packages/kit/src/runtime/navigation/internal.ts similarity index 98% rename from packages/kit/src/client/router/index.ts rename to packages/kit/src/runtime/navigation/internal.ts index dd41d7bd1937..2720490f1ce2 100644 --- a/packages/kit/src/client/router/index.ts +++ b/packages/kit/src/runtime/navigation/internal.ts @@ -1,5 +1,5 @@ -import { ScrollPosition, Target } from '../types'; -import find_anchor from './find_anchor'; +import { ScrollPosition, Target } from './types'; +import { find_anchor } from './utils'; import { routes } from 'MANIFEST'; // TODO diff --git a/packages/kit/src/client/prefetch/index.ts b/packages/kit/src/runtime/navigation/prefetch/index.ts similarity index 86% rename from packages/kit/src/client/prefetch/index.ts rename to packages/kit/src/runtime/navigation/prefetch/index.ts index 4b8f43672098..543f37b6c829 100644 --- a/packages/kit/src/client/prefetch/index.ts +++ b/packages/kit/src/runtime/navigation/prefetch/index.ts @@ -1,8 +1,7 @@ -import { hydrate_target } from '../app'; -import { select_target } from '../router'; -import find_anchor from '../router/find_anchor'; +import { hydrate_target } from '../start'; // TODO does this belong here? +import { select_target } from '../internal'; +import { find_anchor, get_base_uri } from '../utils'; import { HydratedTarget, Target } from '../types'; -import { get_base_uri } from '../baseuri_helper'; let prefetching: { href: string; diff --git a/packages/kit/src/client/prefetchRoutes/index.ts b/packages/kit/src/runtime/navigation/prefetchRoutes/index.ts similarity index 100% rename from packages/kit/src/client/prefetchRoutes/index.ts rename to packages/kit/src/runtime/navigation/prefetchRoutes/index.ts diff --git a/packages/kit/src/client/app.ts b/packages/kit/src/runtime/navigation/start/index.ts similarity index 96% rename from packages/kit/src/client/app.ts rename to packages/kit/src/runtime/navigation/start/index.ts index d9448041ca89..00e63ee0a387 100644 --- a/packages/kit/src/client/app.ts +++ b/packages/kit/src/runtime/navigation/start/index.ts @@ -1,9 +1,9 @@ import { writable } from 'svelte/store'; -import { extract_query, init as init_router, load_current_page, select_target } from './router'; -import { get_prefetched, start as start_prefetching } from './prefetch'; -import { HydratedTarget, Target, Redirect, Branch, Page, InitialData } from './types'; -import goto from './goto'; -import { page_store } from './stores'; +import { extract_query, init as init_router, load_current_page, select_target } from '../internal'; +import { get_prefetched, start as start_prefetching } from '../prefetch'; +import { HydratedTarget, Target, Redirect, Branch, Page, InitialData } from '../types'; +import goto from '../goto'; +import { page_store } from './page_store'; import { ErrorComponent, components } from 'MANIFEST'; import root from 'ROOT'; diff --git a/packages/kit/src/client/stores/index.ts b/packages/kit/src/runtime/navigation/start/page_store.ts similarity index 100% rename from packages/kit/src/client/stores/index.ts rename to packages/kit/src/runtime/navigation/start/page_store.ts diff --git a/packages/kit/src/client/types.ts b/packages/kit/src/runtime/navigation/types.ts similarity index 100% rename from packages/kit/src/client/types.ts rename to packages/kit/src/runtime/navigation/types.ts diff --git a/packages/kit/src/client/baseuri_helper.ts b/packages/kit/src/runtime/navigation/utils.ts similarity index 59% rename from packages/kit/src/client/baseuri_helper.ts rename to packages/kit/src/runtime/navigation/utils.ts index 03cfc436fa26..2fcf5574e725 100644 --- a/packages/kit/src/client/baseuri_helper.ts +++ b/packages/kit/src/runtime/navigation/utils.ts @@ -8,3 +8,8 @@ export function get_base_uri(window_document) { return baseURI; } + +export function find_anchor(node: Node) { + while (node && node.nodeName.toUpperCase() !== 'A') node = node.parentNode; // SVG elements have a lowercase name + return node; +} diff --git a/packages/kit/src/runtime/stores/index.ts b/packages/kit/src/runtime/stores/index.ts new file mode 100644 index 000000000000..ef1afc7ebcbf --- /dev/null +++ b/packages/kit/src/runtime/stores/index.ts @@ -0,0 +1,43 @@ +import { getContext } from 'svelte'; + +// const ssr = (import.meta as any).env.SSR; +const ssr = typeof window === 'undefined'; // TODO why doesn't previous line work in build? + +export const getStores: () => { + page: any // TODO + preloading: any // TODO + session: any // TODO +} = () => getContext('__svelte__'); + +export const page = { + subscribe(fn) { + const store = getStores().page; + return store.subscribe(fn); + } +}; + +export const preloading = { + subscribe(fn) { + const store = getStores().preloading; + return store.subscribe(fn); + } +}; + +const error = verb => { + throw new Error(ssr ? `Can only ${verb} session store in browser` : `Cannot ${verb} session store before subscribing`); +}; + +export const session = { + subscribe(fn) { + const store = getStores().session; + + if (!ssr) { + session.set = store.set; + session.update = store.update; + } + + return store.subscribe(fn); + }, + set: () => error('set'), + update: () => error('update') +}; \ No newline at end of file diff --git a/packages/kit/tsconfig.json b/packages/kit/tsconfig.json index 29d4d3b9c173..e1376e178d23 100644 --- a/packages/kit/tsconfig.json +++ b/packages/kit/tsconfig.json @@ -5,8 +5,10 @@ "moduleResolution": "node", "target": "ES6", "esModuleInterop": true, - "noEmit": true + "noEmit": true, + "noEmitOnError": true }, "include": ["src/**/*"], - "lib": ["ES2020", "dom", "node"] + "lib": ["ES2020", "dom", "node"], + "strict": true } diff --git a/packages/snowpack-config/snowpack.config.js b/packages/snowpack-config/snowpack.config.js index 521186b3abc8..91f78d2a6ae9 100644 --- a/packages/snowpack-config/snowpack.config.js +++ b/packages/snowpack-config/snowpack.config.js @@ -25,7 +25,7 @@ module.exports = { 'src/setup': '/_app/setup' }, alias: { - '@sveltejs/kit': '/_app/main', + $app: '/_app/main/runtime', $components: './src/components' } }; \ No newline at end of file