diff --git a/.gitignore b/.gitignore index 8a4d1d070e..cc2e05ea5f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .idea .DS_Store -.vscode +.vscode/* +!.vscode/launch.json node_modules .eslintcache diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000000..2e22a5ab9b --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,27 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "chrome", + "request": "launch", + "name": "Playground: Browser", + "url": "http://localhost:10001" + }, + { + "type": "node", + "request": "launch", + "runtimeArgs": ["--watch"], + "name": "Playground: Server", + "outputCapture": "std", + "program": "start.js", + "cwd": "${workspaceFolder}/packages/playground", + "cascadeTerminateToConfigurations": ["Playground: Browser"] + } + ], + "compounds": [ + { + "name": "Playground: Full", + "configurations": ["Playground: Server", "Playground: Browser"] + } + ] +} diff --git a/packages/playground/.gitignore b/packages/playground/.gitignore new file mode 100644 index 0000000000..0212d8b6ce --- /dev/null +++ b/packages/playground/.gitignore @@ -0,0 +1,3 @@ +dist +dist-ssr +*.local diff --git a/packages/playground/README.md b/packages/playground/README.md new file mode 100644 index 0000000000..6ac0393720 --- /dev/null +++ b/packages/playground/README.md @@ -0,0 +1,7 @@ +You may use this package to experiment with your changes to Svelte. + +To prevent any changes you make in this directory from being accidentally committed, run `git update-index --skip-worktree ./**/*.*` in this directory. + +If you would actually like to make some changes to the files here for everyone then run `git update-index --no-skip-worktree ./**/*.*` before committing. + +If you're using VS Code, you can use the "Playground: Full" launch configuration to run the playground and attach the debugger to both the compiler and the browser. diff --git a/packages/playground/jsconfig.json b/packages/playground/jsconfig.json new file mode 100644 index 0000000000..ba142a7d31 --- /dev/null +++ b/packages/playground/jsconfig.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "moduleResolution": "Node", + "target": "ESNext", + "module": "ESNext", + /** + * svelte-preprocess cannot figure out whether you have + * a value or a type, so tell TypeScript to enforce using + * `import type` instead of `import` for Types. + */ + "verbatimModuleSyntax": true, + "isolatedModules": true, + "resolveJsonModule": true, + /** + * To have warnings / errors of the Svelte compiler at the + * correct position, enable source maps by default. + */ + "sourceMap": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable this if you'd like to use dynamic types. + */ + "checkJs": true + }, + /** + * Use global.d.ts instead of compilerOptions.types + * to avoid limiting type declarations. + */ + "include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.svelte"] +} diff --git a/packages/playground/package.json b/packages/playground/package.json new file mode 100644 index 0000000000..9c1f03db20 --- /dev/null +++ b/packages/playground/package.json @@ -0,0 +1,14 @@ +{ + "name": "playground", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "node --watch start.js" + }, + "devDependencies": { + "rollup": "^3.20.2", + "rollup-plugin-serve": "^2.0.2", + "svelte": "workspace:*" + } +} diff --git a/packages/playground/src/App.svelte b/packages/playground/src/App.svelte new file mode 100644 index 0000000000..ab87de6d96 --- /dev/null +++ b/packages/playground/src/App.svelte @@ -0,0 +1,3 @@ +
+ Hello world! +
\ No newline at end of file diff --git a/packages/playground/src/entry-client.js b/packages/playground/src/entry-client.js new file mode 100644 index 0000000000..e62bbf2eb7 --- /dev/null +++ b/packages/playground/src/entry-client.js @@ -0,0 +1,24 @@ +import App from './App.svelte'; + +new App({ + target: document.getElementById('app'), + hydrate: true +}); + +function get_version() { + return fetch('/version.json').then((r) => r.json()); +} + +let prev = await get_version(); + +// Mom: We have live reloading at home +// Live reloading at home: +while (true) { + await new Promise((r) => setTimeout(r, 2500)); + try { + const version = await get_version(); + if (prev !== version) { + window.location.reload(); + } + } catch {} +} diff --git a/packages/playground/src/entry-server.js b/packages/playground/src/entry-server.js new file mode 100644 index 0000000000..7402e1e9ad --- /dev/null +++ b/packages/playground/src/entry-server.js @@ -0,0 +1,6 @@ +import App from './App.svelte'; + +export function render() { + // @ts-ignore + return App.render(); +} diff --git a/packages/playground/src/lib/Counter.svelte b/packages/playground/src/lib/Counter.svelte new file mode 100644 index 0000000000..e45f903109 --- /dev/null +++ b/packages/playground/src/lib/Counter.svelte @@ -0,0 +1,10 @@ + + + diff --git a/packages/playground/src/template.html b/packages/playground/src/template.html new file mode 100644 index 0000000000..2cc688066f --- /dev/null +++ b/packages/playground/src/template.html @@ -0,0 +1,13 @@ + + + + + + <!--app-title--> + + + +
+ + + diff --git a/packages/playground/start.js b/packages/playground/start.js new file mode 100644 index 0000000000..4144ba97ac --- /dev/null +++ b/packages/playground/start.js @@ -0,0 +1,100 @@ +import { readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { watch } from 'rollup'; +import serve from 'rollup-plugin-serve'; +import * as svelte from '../svelte/src/compiler/index.js'; + +const __dirname = new URL('.', import.meta.url).pathname; + +/** @returns {import('rollup').Plugin}*/ +function create_plugin(ssr = false) { + return { + name: 'custom-svelte-ssr-' + ssr, + resolveId(id) { + if (id === 'svelte') { + return path.resolve( + __dirname, + ssr ? '../svelte/src/runtime/ssr.js' : '../svelte/src/runtime/index.js' + ); + } else if (id.startsWith('svelte/')) { + return path.resolve(__dirname, `../svelte/src/runtime/${id.slice(7)}/index.js`); + } + }, + transform(code, id) { + code = code.replaceAll('import.meta.env.SSR', ssr); + + if (!id.endsWith('.svelte')) { + return { + code, + map: null + }; + } + + const compiled = svelte.compile(code, { + filename: id, + generate: ssr ? 'ssr' : 'dom', + hydratable: true, + css: 'injected' + }); + + return compiled.js; + } + }; +} + +const client_plugin = create_plugin(); +const ssr_plugin = create_plugin(true); + +const watcher = watch([ + { + input: 'src/entry-client.js', + output: { + dir: 'dist', + format: 'esm', + sourcemap: true + }, + plugins: [client_plugin, serve('dist')] + }, + { + input: 'src/entry-server.js', + output: { + dir: 'dist-ssr', + format: 'iife', + indent: false + }, + plugins: [ + ssr_plugin, + { + async generateBundle(_, bundle) { + const result = bundle['entry-server.js']; + const mod = (0, eval)(result.code); + const { html } = mod.render(); + + writeFileSync( + 'dist/index.html', + readFileSync('src/template.html', 'utf-8') + .replace('', html) + .replace('', svelte.VERSION) + ); + writeFileSync('dist/version.json', Date.now().toString()); + } + } + ], + onwarn(warning, handler) { + if (warning.code === 'MISSING_NAME_OPTION_FOR_IIFE_EXPORT') return; + handler(warning); + } + } +]); + +watcher + .on('change', (id) => { + console.log(`changed ${id}`); + }) + .on('event', (event) => { + if (event.code === 'ERROR') { + console.error(event.error); + } else if (event.code === 'BUNDLE_END') { + console.log(`Generated ${event.output} in ${event.duration}ms`); + } + }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dcf3298935..cbec4fcac6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -36,6 +36,18 @@ importers: specifier: ^2.10.0 version: 2.10.0(prettier@2.8.8)(svelte@3.59.1) + packages/playground: + devDependencies: + rollup: + specifier: ^3.20.2 + version: 3.23.0 + rollup-plugin-serve: + specifier: ^2.0.2 + version: 2.0.2 + svelte: + specifier: workspace:* + version: link:../svelte + packages/svelte: dependencies: '@ampproject/remapping': @@ -3012,6 +3024,12 @@ packages: mime-db: 1.52.0 dev: true + /mime@3.0.0: + resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} + engines: {node: '>=10.0.0'} + hasBin: true + dev: true + /min-indent@1.0.1: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} @@ -3143,6 +3161,11 @@ packages: wrappy: 1.0.2 dev: true + /opener@1.5.2: + resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==} + hasBin: true + dev: true + /optionator@0.8.3: resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==} engines: {node: '>= 0.8.0'} @@ -3560,6 +3583,13 @@ packages: glob: 7.2.3 dev: true + /rollup-plugin-serve@2.0.2: + resolution: {integrity: sha512-ALqyTbPhlf7FZ5RzlbDvMYvbKuCHWginJkTo6dMsbgji/a78IbsXox+pC83HENdkTRz8OXrTj+aShp3+3ratpg==} + dependencies: + mime: 3.0.0 + opener: 1.5.2 + dev: true + /rollup@3.23.0: resolution: {integrity: sha512-h31UlwEi7FHihLe1zbk+3Q7z1k/84rb9BSwmBSr/XjOCEaBJ2YyedQDuM0t/kfOS0IxM+vk1/zI9XxYj9V+NJQ==} engines: {node: '>=14.18.0', npm: '>=8.0.0'}