From 1c780ceb498c95a376682fd9b4c46e70c692221c Mon Sep 17 00:00:00 2001 From: Dominik G Date: Fri, 2 Dec 2022 17:30:08 +0100 Subject: [PATCH] feat: support additional queries (#513) * feat: support direct and raw query parameters for svelte requests * wip: add option to pass compileOptions for raw scripts, fix issues with output as default export, add tests * wip: move handling of raw and direct to load hook, change tests to use external snapshot and add more tests * wip: add sourcemap query and inline sourcemaps to direct requests. improve error handling * wip: clean up implementation; add documentation * fix: make sure to return all affected modules from handleHotUpdate instead of just looking at js and css. This updates ?raw imports correctly during dev * feat: add new type 'all' that returns source and complete result with preprocessed, js, css, dependencies and ast * fix: heal pnpm-lock * fix: improve snapshot normalization, sourcemap output included absolute path to testDir, which differs between serve and build tests * fix: avoid absolute paths in sourcemap sources * fix: windows * fix: pass normalizedFilename to svelte compiler so windows compile does not add full absolute path to generated by comment * fix: update snapshots * docs: mark raw&svelte and direct&svelte as experimental * fix: vite ?raw is string by default, so export code string as default and others as named exports * fix: sort exports and don't run mixed tests during build --- .changeset/fresh-papayas-change.md | 5 + .changeset/giant-tools-hunt.md | 5 + .gitattributes | 1 + docs/advanced-usage.md | 125 ++ .../__snapshots__/import-queries.spec.ts.snap | 1118 +++++++++++++++++ .../__tests__/import-queries.spec.ts | 164 +++ packages/e2e-tests/import-queries/index.html | 13 + .../e2e-tests/import-queries/package.json | 17 + .../import-queries/public/favicon.png | Bin 0 -> 3127 bytes .../e2e-tests/import-queries/src/App.svelte | 26 + .../e2e-tests/import-queries/src/Dummy.svelte | 17 + packages/e2e-tests/import-queries/src/main.js | 7 + .../import-queries/src/vite-env.d.ts | 2 + .../e2e-tests/import-queries/svelte.config.js | 12 + .../e2e-tests/import-queries/vite.config.js | 28 + packages/e2e-tests/testUtils.ts | 4 + .../src/handle-hot-update.ts | 48 +- packages/vite-plugin-svelte/src/index.ts | 46 +- .../vite-plugin-svelte/src/utils/compile.ts | 94 +- packages/vite-plugin-svelte/src/utils/id.ts | 58 +- .../vite-plugin-svelte/src/utils/load-raw.ts | 132 ++ .../src/utils/preprocess.ts | 6 +- pnpm-lock.yaml | 12 + 23 files changed, 1861 insertions(+), 79 deletions(-) create mode 100644 .changeset/fresh-papayas-change.md create mode 100644 .changeset/giant-tools-hunt.md create mode 100644 .gitattributes create mode 100644 docs/advanced-usage.md create mode 100644 packages/e2e-tests/import-queries/__tests__/__snapshots__/import-queries.spec.ts.snap create mode 100644 packages/e2e-tests/import-queries/__tests__/import-queries.spec.ts create mode 100644 packages/e2e-tests/import-queries/index.html create mode 100644 packages/e2e-tests/import-queries/package.json create mode 100644 packages/e2e-tests/import-queries/public/favicon.png create mode 100644 packages/e2e-tests/import-queries/src/App.svelte create mode 100644 packages/e2e-tests/import-queries/src/Dummy.svelte create mode 100644 packages/e2e-tests/import-queries/src/main.js create mode 100644 packages/e2e-tests/import-queries/src/vite-env.d.ts create mode 100644 packages/e2e-tests/import-queries/svelte.config.js create mode 100644 packages/e2e-tests/import-queries/vite.config.js create mode 100644 packages/vite-plugin-svelte/src/utils/load-raw.ts diff --git a/.changeset/fresh-papayas-change.md b/.changeset/fresh-papayas-change.md new file mode 100644 index 000000000..33271b0bf --- /dev/null +++ b/.changeset/fresh-papayas-change.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/vite-plugin-svelte': patch +--- + +ensure sources paths in sourcemaps are not absolute file paths diff --git a/.changeset/giant-tools-hunt.md b/.changeset/giant-tools-hunt.md new file mode 100644 index 000000000..dbad90906 --- /dev/null +++ b/.changeset/giant-tools-hunt.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/vite-plugin-svelte': minor +--- + +support `&direct` and `&raw` query parameters for svelte requests diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..6313b56c5 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md new file mode 100644 index 000000000..9e9906351 --- /dev/null +++ b/docs/advanced-usage.md @@ -0,0 +1,125 @@ +# Advanced usage + +> **HERE BE DRAGONS** +> +> The features described here are not meant to be used in regular libraries or end-user applications. +> They can be useful for frameworks, documentation sites or in special situations, but you are responsible for applying them correctly. +> +> **Proceed with caution!** + +## custom queries + +Vite supports using query parameters to request different outcomes for the same file. + +The following schemes are supported by vite-plugin-svelte: + +### raw + +```js +//get .svelte file content as a string +import content from 'File.svelte?raw'; +``` + +### experimental + +In addition to the plain .svelte source content, you can use special svelte queries. + +> These svelte subqueries are experimental, availability, syntax and output format may change + +#### raw&svelte + +```js +//get output of svelte.preprocess code as string +import preprocessed from 'File.svelte?raw&svelte&type=preprocessed'; +``` + +```js +//get output of svelte.compile js.code as string +import script from 'File.svelte?raw&svelte&type=script'; +``` + +```js +//get output of svelte.compile css.code as string +import style from 'File.svelte?raw&svelte&type=style'; +``` + +##### detail exports + +raw&svelte exports code string as default export, but also offers named exports if you need details + +```js +//get output of svelte.preprocess +import { code, map, dependencies } from 'File.svelte?raw&svelte&type=preprocessed'; +``` + +```js +//get output of svelte.compile js +import { code, map, dependencies } from 'File.svelte?raw&svelte&type=script'; +``` + +```js +//get output of svelte.compile css +import { code, map, dependencies } from 'File.svelte?raw&svelte&type=style'; +``` + +```js +//get everything in one go +import * as all from 'File.svelte?raw&svelte&type=all'; +import { + source, + preprocessed, + dependencies, + js, + css, + ast, + normalizedFilename, + ssr, + lang, + warnings, + stats +} from 'File.svelte?raw&svelte&type=all'; +``` + +#### direct&svelte + +```html + + + + + + +" +`; + +exports[`raw > Dummy.svelte?raw&svelte&type=all&sourcemap 1`] = ` +"{ + \\"ast\\": { + \\"html\\": { + \\"start\\": 62, + \\"end\\": 138, + \\"type\\": \\"Fragment\\", + \\"children\\": [ + { + \\"start\\": 60, + \\"end\\": 62, + \\"type\\": \\"Text\\", + \\"raw\\": \\"\\\\n\\\\n\\", + \\"data\\": \\"\\\\n\\\\n\\" + }, + { + \\"start\\": 62, + \\"end\\": 138, + \\"type\\": \\"Element\\", + \\"name\\": \\"button\\", + \\"attributes\\": [ + { + \\"start\\": 71, + \\"end\\": 104, + \\"type\\": \\"EventHandler\\", + \\"name\\": \\"click\\", + \\"modifiers\\": [], + \\"expression\\": { + \\"type\\": \\"ArrowFunctionExpression\\", + \\"start\\": 81, + \\"end\\": 103, + \\"loc\\": { + \\"start\\": { + \\"line\\": 6, + \\"column\\": 11 + }, + \\"end\\": { + \\"line\\": 8, + \\"column\\": 2 + } + }, + \\"id\\": null, + \\"expression\\": false, + \\"generator\\": false, + \\"async\\": false, + \\"params\\": [], + \\"body\\": { + \\"type\\": \\"BlockStatement\\", + \\"start\\": 87, + \\"end\\": 103, + \\"loc\\": { + \\"start\\": { + \\"line\\": 6, + \\"column\\": 17 + }, + \\"end\\": { + \\"line\\": 8, + \\"column\\": 2 + } + }, + \\"body\\": [ + { + \\"type\\": \\"ExpressionStatement\\", + \\"start\\": 91, + \\"end\\": 100, + \\"loc\\": { + \\"start\\": { + \\"line\\": 7, + \\"column\\": 2 + }, + \\"end\\": { + \\"line\\": 7, + \\"column\\": 11 + } + }, + \\"expression\\": { + \\"type\\": \\"UpdateExpression\\", + \\"start\\": 91, + \\"end\\": 99, + \\"loc\\": { + \\"start\\": { + \\"line\\": 7, + \\"column\\": 2 + }, + \\"end\\": { + \\"line\\": 7, + \\"column\\": 10 + } + }, + \\"operator\\": \\"++\\", + \\"prefix\\": false, + \\"argument\\": { + \\"type\\": \\"Identifier\\", + \\"start\\": 91, + \\"end\\": 97, + \\"loc\\": { + \\"start\\": { + \\"line\\": 7, + \\"column\\": 2 + }, + \\"end\\": { + \\"line\\": 7, + \\"column\\": 8 + } + }, + \\"name\\": \\"clicks\\" + } + } + } + ] + } + } + } + ], + \\"children\\": [ + { + \\"start\\": 105, + \\"end\\": 111, + \\"type\\": \\"MustacheTag\\", + \\"expression\\": { + \\"type\\": \\"Identifier\\", + \\"start\\": 106, + \\"end\\": 110, + \\"loc\\": { + \\"start\\": { + \\"line\\": 8, + \\"column\\": 5 + }, + \\"end\\": { + \\"line\\": 8, + \\"column\\": 9 + } + }, + \\"name\\": \\"name\\" + } + }, + { + \\"start\\": 111, + \\"end\\": 120, + \\"type\\": \\"Text\\", + \\"raw\\": \\" clicks: \\", + \\"data\\": \\" clicks: \\" + }, + { + \\"start\\": 120, + \\"end\\": 128, + \\"type\\": \\"MustacheTag\\", + \\"expression\\": { + \\"type\\": \\"Identifier\\", + \\"start\\": 121, + \\"end\\": 127, + \\"loc\\": { + \\"start\\": { + \\"line\\": 8, + \\"column\\": 20 + }, + \\"end\\": { + \\"line\\": 8, + \\"column\\": 26 + } + }, + \\"name\\": \\"clicks\\" + } + } + ] + }, + { + \\"start\\": 138, + \\"end\\": 140, + \\"type\\": \\"Text\\", + \\"raw\\": \\"\\\\n\\\\n\\", + \\"data\\": \\"\\\\n\\\\n\\" + } + ] + }, + \\"css\\": { + \\"type\\": \\"Style\\", + \\"start\\": 140, + \\"end\\": 195, + \\"attributes\\": [ + { + \\"start\\": 147, + \\"end\\": 158, + \\"type\\": \\"Attribute\\", + \\"name\\": \\"lang\\", + \\"value\\": [ + { + \\"start\\": 153, + \\"end\\": 157, + \\"type\\": \\"Text\\", + \\"raw\\": \\"scss\\", + \\"data\\": \\"scss\\" + } + ] + } + ], + \\"children\\": [ + { + \\"type\\": \\"Rule\\", + \\"prelude\\": { + \\"type\\": \\"SelectorList\\", + \\"children\\": [ + { + \\"type\\": \\"Selector\\", + \\"children\\": [ + { + \\"type\\": \\"TypeSelector\\", + \\"name\\": \\"button\\", + \\"start\\": 159, + \\"end\\": 165 + } + ], + \\"start\\": 159, + \\"end\\": 165 + } + ], + \\"start\\": 159, + \\"end\\": 165 + }, + \\"block\\": { + \\"type\\": \\"Block\\", + \\"children\\": [ + { + \\"type\\": \\"Declaration\\", + \\"important\\": false, + \\"property\\": \\"color\\", + \\"value\\": { + \\"type\\": \\"Value\\", + \\"children\\": [ + { + \\"type\\": \\"Hash\\", + \\"value\\": \\"000099\\", + \\"start\\": 177, + \\"end\\": 184 + } + ], + \\"start\\": 177, + \\"end\\": 184 + }, + \\"start\\": 170, + \\"end\\": 184 + } + ], + \\"start\\": 166, + \\"end\\": 187 + }, + \\"start\\": 159, + \\"end\\": 187 + } + ], + \\"content\\": { + \\"start\\": 159, + \\"end\\": 187, + \\"styles\\": \\"button {\\\\n color: #000099;\\\\n}\\" + } + }, + \\"instance\\": { + \\"type\\": \\"Script\\", + \\"start\\": 0, + \\"end\\": 60, + \\"context\\": \\"default\\", + \\"content\\": { + \\"type\\": \\"Program\\", + \\"start\\": 18, + \\"end\\": 51, + \\"loc\\": { + \\"start\\": { + \\"line\\": 1, + \\"column\\": 0 + }, + \\"end\\": { + \\"line\\": 3, + \\"column\\": 0 + } + }, + \\"body\\": [ + { + \\"type\\": \\"ExportNamedDeclaration\\", + \\"start\\": 18, + \\"end\\": 34, + \\"loc\\": { + \\"start\\": { + \\"line\\": 1, + \\"column\\": 18 + }, + \\"end\\": { + \\"line\\": 1, + \\"column\\": 34 + } + }, + \\"declaration\\": { + \\"type\\": \\"VariableDeclaration\\", + \\"start\\": 25, + \\"end\\": 34, + \\"loc\\": { + \\"start\\": { + \\"line\\": 1, + \\"column\\": 25 + }, + \\"end\\": { + \\"line\\": 1, + \\"column\\": 34 + } + }, + \\"declarations\\": [ + { + \\"type\\": \\"VariableDeclarator\\", + \\"start\\": 29, + \\"end\\": 33, + \\"loc\\": { + \\"start\\": { + \\"line\\": 1, + \\"column\\": 29 + }, + \\"end\\": { + \\"line\\": 1, + \\"column\\": 33 + } + }, + \\"id\\": { + \\"type\\": \\"Identifier\\", + \\"start\\": 29, + \\"end\\": 33, + \\"loc\\": { + \\"start\\": { + \\"line\\": 1, + \\"column\\": 29 + }, + \\"end\\": { + \\"line\\": 1, + \\"column\\": 33 + } + }, + \\"name\\": \\"name\\" + }, + \\"init\\": null + } + ], + \\"kind\\": \\"let\\" + }, + \\"specifiers\\": [], + \\"source\\": null + }, + { + \\"type\\": \\"VariableDeclaration\\", + \\"start\\": 35, + \\"end\\": 50, + \\"loc\\": { + \\"start\\": { + \\"line\\": 2, + \\"column\\": 0 + }, + \\"end\\": { + \\"line\\": 2, + \\"column\\": 15 + } + }, + \\"declarations\\": [ + { + \\"type\\": \\"VariableDeclarator\\", + \\"start\\": 39, + \\"end\\": 49, + \\"loc\\": { + \\"start\\": { + \\"line\\": 2, + \\"column\\": 4 + }, + \\"end\\": { + \\"line\\": 2, + \\"column\\": 14 + } + }, + \\"id\\": { + \\"type\\": \\"Identifier\\", + \\"start\\": 39, + \\"end\\": 45, + \\"loc\\": { + \\"start\\": { + \\"line\\": 2, + \\"column\\": 4 + }, + \\"end\\": { + \\"line\\": 2, + \\"column\\": 10 + } + }, + \\"name\\": \\"clicks\\" + }, + \\"init\\": { + \\"type\\": \\"Literal\\", + \\"start\\": 48, + \\"end\\": 49, + \\"loc\\": { + \\"start\\": { + \\"line\\": 2, + \\"column\\": 13 + }, + \\"end\\": { + \\"line\\": 2, + \\"column\\": 14 + } + }, + \\"value\\": 0, + \\"raw\\": \\"0\\" + } + } + ], + \\"kind\\": \\"let\\" + } + ], + \\"sourceType\\": \\"module\\" + } + } + }, + \\"css\\": { + \\"code\\": \\"button.svelte-d8vj6a{color:#000099}\\", + \\"map\\": { + \\"version\\": 3, + \\"file\\": \\"Dummy.svelte\\", + \\"mappings\\": \\"AAWkB,MAAA,cAAA,CAAA,cAKlB\\", + \\"names\\": [], + \\"sources\\": [ + \\"Dummy.svelte\\" + ] + } + }, + \\"dependencies\\": [], + \\"js\\": { + \\"code\\": \\"/* src/Dummy.svelte generated by Svelte vXXX */\\\\nimport {\\\\n\\\\tSvelteComponent as SvelteComponent$,\\\\n\\\\tappend as append$,\\\\n\\\\tattr as attr$,\\\\n\\\\tdetach as detach$,\\\\n\\\\telement as element$,\\\\n\\\\tinit as init$,\\\\n\\\\tinsert as insert$,\\\\n\\\\tlisten as listen$,\\\\n\\\\tnoop as noop$,\\\\n\\\\tsafe_not_equal as safe_not_equal$,\\\\n\\\\tset_data as set_data$,\\\\n\\\\ttext as text$\\\\n} from \\\\\\"svelte/internal\\\\\\";\\\\n\\\\nfunction create_fragment(ctx) {\\\\n\\\\tlet button$;\\\\n\\\\tlet t0$;\\\\n\\\\tlet t1$;\\\\n\\\\tlet t2$;\\\\n\\\\tlet mounted;\\\\n\\\\tlet dispose;\\\\n\\\\n\\\\treturn {\\\\n\\\\t\\\\tc() {\\\\n\\\\t\\\\t\\\\tbutton$ = element$(\\\\\\"button\\\\\\");\\\\n\\\\t\\\\t\\\\tt0$ = text$(/*name*/ ctx[0]);\\\\n\\\\t\\\\t\\\\tt1$ = text$(\\\\\\" clicks: \\\\\\");\\\\n\\\\t\\\\t\\\\tt2$ = text$(/*clicks*/ ctx[1]);\\\\n\\\\t\\\\t\\\\tattr$(button$, \\\\\\"class\\\\\\", \\\\\\"svelte-d8vj6a\\\\\\");\\\\n\\\\t\\\\t},\\\\n\\\\t\\\\tm(target, anchor) {\\\\n\\\\t\\\\t\\\\tinsert$(target, button$, anchor);\\\\n\\\\t\\\\t\\\\tappend$(button$, t0$);\\\\n\\\\t\\\\t\\\\tappend$(button$, t1$);\\\\n\\\\t\\\\t\\\\tappend$(button$, t2$);\\\\n\\\\n\\\\t\\\\t\\\\tif (!mounted) {\\\\n\\\\t\\\\t\\\\t\\\\tdispose = listen$(button$, \\\\\\"click\\\\\\", /*click_handler$*/ ctx[2]);\\\\n\\\\t\\\\t\\\\t\\\\tmounted = true;\\\\n\\\\t\\\\t\\\\t}\\\\n\\\\t\\\\t},\\\\n\\\\t\\\\tp(ctx, [dirty]) {\\\\n\\\\t\\\\t\\\\tif (dirty & /*name*/ 1) set_data$(t0$, /*name*/ ctx[0]);\\\\n\\\\t\\\\t\\\\tif (dirty & /*clicks*/ 2) set_data$(t2$, /*clicks*/ ctx[1]);\\\\n\\\\t\\\\t},\\\\n\\\\t\\\\ti: noop$,\\\\n\\\\t\\\\to: noop$,\\\\n\\\\t\\\\td(detaching) {\\\\n\\\\t\\\\t\\\\tif (detaching) detach$(button$);\\\\n\\\\t\\\\t\\\\tmounted = false;\\\\n\\\\t\\\\t\\\\tdispose();\\\\n\\\\t\\\\t}\\\\n\\\\t};\\\\n}\\\\n\\\\nfunction instance$($$self, $$props, $$invalidate) {\\\\n\\\\tlet { name } = $$props;\\\\n\\\\tlet clicks = 0;\\\\n\\\\n\\\\tconst click_handler$ = () => {\\\\n\\\\t\\\\t$$invalidate(1, clicks++, clicks);\\\\n\\\\t};\\\\n\\\\n\\\\t$$self.$$set = $$props => {\\\\n\\\\t\\\\tif ('name' in $$props) $$invalidate(0, name = $$props.name);\\\\n\\\\t};\\\\n\\\\n\\\\treturn [name, clicks, click_handler$];\\\\n}\\\\n\\\\nclass Dummy$ extends SvelteComponent$ {\\\\n\\\\tconstructor(options) {\\\\n\\\\t\\\\tsuper();\\\\n\\\\t\\\\tinit$(this, options, instance$, create_fragment, safe_not_equal$, { name: 0 });\\\\n\\\\t}\\\\n}\\\\n\\\\nexport default Dummy$;\\", + \\"map\\": { + \\"version\\": 3, + \\"mappings\\": \\";;;;;;;;;;;;;;;;;;;;;;;;;;;wBAQK,GAAI;eAAC,WAAS;0BAAC,GAAM;;;;GAH1B,OAIA;;;;;;;;;;;mDADK,GAAI;uDAAW,GAAM;;;;;;;;;;;;;OAPd,IAAA;KACP,MAAA,GAAS,CAAA;;;kBAKZ,MAAM;;;;;;;;;;;;;;;;;\\", + \\"names\\": [], + \\"sources\\": [ + \\"Dummy.svelte\\" + ] + }, + \\"dependencies\\": [] + }, + \\"lang\\": \\"ts\\", + \\"normalizedFilename\\": \\"/src/Dummy.svelte\\", + \\"preprocessed\\": { + \\"code\\": \\"\\\\n\\\\n {\\\\n\\\\t\\\\tclicks++;\\\\n\\\\t}}>{name} clicks: {clicks}\\\\n\\\\n\\\\n\\", + \\"dependencies\\": [], + \\"map\\": { + \\"version\\": 3, + \\"mappings\\": \\"AAAA,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CCCT,MAAA,CAAA,GAAA,CAAI,IAAA;AACX,GAAA,CAAI,MAAA,CAAA,CAAA,CAAS,CAAA;ADCd,CAAC,CAAC,MAAM;;AAER,CAAC;AACD,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjB,EAAE,MAAM,CAAC,CAAC;AACV,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAC7B;;AAEA,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;;CAKlB,CAAC,CAAC,KAAK;\\", + \\"names\\": [], + \\"sources\\": [ + \\"Dummy.svelte\\", + \\"Dummy.svelte\\" + ] + } + }, + \\"source\\": \\"\\\\n\\\\n {\\\\n\\\\t\\\\tclicks++;\\\\n\\\\t}}>{name} clicks: {clicks}\\\\n\\\\n\\\\n\\", + \\"ssr\\": false, + \\"stats\\": { + \\"timings\\": { + \\"total\\":0.123456789, + \\"parse\\": { + \\"total\\":0.123456789 + }, + \\"create component\\": { + \\"total\\":0.123456789 + } + } + }, + \\"vars\\": [ + { + \\"name\\": \\"name\\", + \\"export_name\\": \\"name\\", + \\"injected\\": false, + \\"module\\": false, + \\"mutated\\": false, + \\"reassigned\\": false, + \\"referenced\\": true, + \\"writable\\": true, + \\"referenced_from_script\\": false + }, + { + \\"name\\": \\"clicks\\", + \\"export_name\\": null, + \\"injected\\": false, + \\"module\\": false, + \\"mutated\\": false, + \\"reassigned\\": true, + \\"referenced\\": true, + \\"writable\\": true, + \\"referenced_from_script\\": false + } + ], + \\"warnings\\": [] +}" +`; + +exports[`raw > Dummy.svelte?raw&svelte&type=preprocessed 1`] = ` +" + + + + +" +`; + +exports[`raw > Dummy.svelte?raw&svelte&type=script 1`] = ` +"/* src/Dummy.svelte generated by Svelte vXXX */ +import { + SvelteComponent as SvelteComponent$, + append as append$, + attr as attr$, + detach as detach$, + element as element$, + init as init$, + insert as insert$, + listen as listen$, + noop as noop$, + safe_not_equal as safe_not_equal$, + set_data as set_data$, + text as text$ +} from \\"svelte/internal\\"; + +function create_fragment(ctx) { + let button$; + let t0$; + let t1$; + let t2$; + let mounted; + let dispose; + + return { + c() { + button$ = element$(\\"button\\"); + t0$ = text$(/*name*/ ctx[0]); + t1$ = text$(\\" clicks: \\"); + t2$ = text$(/*clicks*/ ctx[1]); + attr$(button$, \\"class\\", \\"svelte-d8vj6a\\"); + }, + m(target, anchor) { + insert$(target, button$, anchor); + append$(button$, t0$); + append$(button$, t1$); + append$(button$, t2$); + + if (!mounted) { + dispose = listen$(button$, \\"click\\", /*click_handler$*/ ctx[2]); + mounted = true; + } + }, + p(ctx, [dirty]) { + if (dirty & /*name*/ 1) set_data$(t0$, /*name*/ ctx[0]); + if (dirty & /*clicks*/ 2) set_data$(t2$, /*clicks*/ ctx[1]); + }, + i: noop$, + o: noop$, + d(detaching) { + if (detaching) detach$(button$); + mounted = false; + dispose(); + } + }; +} + +function instance$($$self, $$props, $$invalidate) { + let { name } = $$props; + let clicks = 0; + + const click_handler$ = () => { + $$invalidate(1, clicks++, clicks); + }; + + $$self.$$set = $$props => { + if ('name' in $$props) $$invalidate(0, name = $$props.name); + }; + + return [name, clicks, click_handler$]; +} + +class Dummy$ extends SvelteComponent$ { + constructor(options) { + super(); + init$(this, options, instance$, create_fragment, safe_not_equal$, { name: 0 }); + } +} + +export default Dummy$;" +`; + +exports[`raw > Dummy.svelte?raw&svelte&type=script&compilerOptions={"customElement":true} 1`] = ` +"/* src/Dummy.svelte generated by Svelte vXXX */ +import { + SvelteElement as SvelteElement$, + append as append$, + attribute_to_object as attribute_to_object$, + detach as detach$, + element as element$, + flush as flush$, + init as init$, + insert as insert$, + listen as listen$, + noop as noop$, + safe_not_equal as safe_not_equal$, + set_data as set_data$, + text as text$ +} from \\"svelte/internal\\"; + +function create_fragment(ctx) { + let button$; + let t0$; + let t1$; + let t2$; + let mounted; + let dispose; + + return { + c() { + button$ = element$(\\"button\\"); + t0$ = text$(/*name*/ ctx[0]); + t1$ = text$(\\" clicks: \\"); + t2$ = text$(/*clicks*/ ctx[1]); + this.c = noop$; + }, + m(target, anchor) { + insert$(target, button$, anchor); + append$(button$, t0$); + append$(button$, t1$); + append$(button$, t2$); + + if (!mounted) { + dispose = listen$(button$, \\"click\\", /*click_handler$*/ ctx[2]); + mounted = true; + } + }, + p(ctx, [dirty]) { + if (dirty & /*name*/ 1) set_data$(t0$, /*name*/ ctx[0]); + if (dirty & /*clicks*/ 2) set_data$(t2$, /*clicks*/ ctx[1]); + }, + i: noop$, + o: noop$, + d(detaching) { + if (detaching) detach$(button$); + mounted = false; + dispose(); + } + }; +} + +function instance$($$self, $$props, $$invalidate) { + let { name } = $$props; + let clicks = 0; + + const click_handler$ = () => { + $$invalidate(1, clicks++, clicks); + }; + + $$self.$$set = $$props => { + if ('name' in $$props) $$invalidate(0, name = $$props.name); + }; + + return [name, clicks, click_handler$]; +} + +class Dummy$ extends SvelteElement$ { + constructor(options) { + super(); + this.shadowRoot.innerHTML = \`\`; + + init$( + this, + { + target: this.shadowRoot, + props: attribute_to_object$(this.attributes), + customElement: true + }, + instance$, + create_fragment, + safe_not_equal$, + { name: 0 }, + null + ); + + if (options) { + if (options.target) { + insert$(options.target, this, options.anchor); + } + + if (options.props) { + this.$set(options.props); + flush$(); + } + } + } + + static get observedAttributes() { + return [\\"name\\"]; + } + + get name() { + return this.$$.ctx[0]; + } + + set name(name) { + this.$$set({ name }); + flush$(); + } +} + +export default Dummy$;" +`; + +exports[`raw > Dummy.svelte?raw&svelte&type=style 1`] = `"button.svelte-d8vj6a{color:#000099}"`; + +exports[`raw > mixed exports > Dummy.svelte?raw&svelte&type=all 1`] = ` +"export const ast={\\"html\\":{\\"start\\":62,\\"end\\":138,\\"type\\":\\"Fragment\\",\\"children\\":[{\\"start\\":60,\\"end\\":62,\\"type\\":\\"Text\\",\\"raw\\":\\"\\\\n\\\\n\\",\\"data\\":\\"\\\\n\\\\n\\"},{\\"start\\":62,\\"end\\":138,\\"type\\":\\"Element\\",\\"name\\":\\"button\\",\\"attributes\\":[{\\"start\\":71,\\"end\\":104,\\"type\\":\\"EventHandler\\",\\"name\\":\\"click\\",\\"modifiers\\":[],\\"expression\\":{\\"type\\":\\"ArrowFunctionExpression\\",\\"start\\":81,\\"end\\":103,\\"loc\\":{\\"start\\":{\\"line\\":6,\\"column\\":11},\\"end\\":{\\"line\\":8,\\"column\\":2}},\\"id\\":null,\\"expression\\":false,\\"generator\\":false,\\"async\\":false,\\"params\\":[],\\"body\\":{\\"type\\":\\"BlockStatement\\",\\"start\\":87,\\"end\\":103,\\"loc\\":{\\"start\\":{\\"line\\":6,\\"column\\":17},\\"end\\":{\\"line\\":8,\\"column\\":2}},\\"body\\":[{\\"type\\":\\"ExpressionStatement\\",\\"start\\":91,\\"end\\":100,\\"loc\\":{\\"start\\":{\\"line\\":7,\\"column\\":2},\\"end\\":{\\"line\\":7,\\"column\\":11}},\\"expression\\":{\\"type\\":\\"UpdateExpression\\",\\"start\\":91,\\"end\\":99,\\"loc\\":{\\"start\\":{\\"line\\":7,\\"column\\":2},\\"end\\":{\\"line\\":7,\\"column\\":10}},\\"operator\\":\\"++\\",\\"prefix\\":false,\\"argument\\":{\\"type\\":\\"Identifier\\",\\"start\\":91,\\"end\\":97,\\"loc\\":{\\"start\\":{\\"line\\":7,\\"column\\":2},\\"end\\":{\\"line\\":7,\\"column\\":8}},\\"name\\":\\"clicks\\"}}}]}}}],\\"children\\":[{\\"start\\":105,\\"end\\":111,\\"type\\":\\"MustacheTag\\",\\"expression\\":{\\"type\\":\\"Identifier\\",\\"start\\":106,\\"end\\":110,\\"loc\\":{\\"start\\":{\\"line\\":8,\\"column\\":5},\\"end\\":{\\"line\\":8,\\"column\\":9}},\\"name\\":\\"name\\"}},{\\"start\\":111,\\"end\\":120,\\"type\\":\\"Text\\",\\"raw\\":\\" clicks: \\",\\"data\\":\\" clicks: \\"},{\\"start\\":120,\\"end\\":128,\\"type\\":\\"MustacheTag\\",\\"expression\\":{\\"type\\":\\"Identifier\\",\\"start\\":121,\\"end\\":127,\\"loc\\":{\\"start\\":{\\"line\\":8,\\"column\\":20},\\"end\\":{\\"line\\":8,\\"column\\":26}},\\"name\\":\\"clicks\\"}}]},{\\"start\\":138,\\"end\\":140,\\"type\\":\\"Text\\",\\"raw\\":\\"\\\\n\\\\n\\",\\"data\\":\\"\\\\n\\\\n\\"}]},\\"css\\":{\\"type\\":\\"Style\\",\\"start\\":140,\\"end\\":195,\\"attributes\\":[{\\"start\\":147,\\"end\\":158,\\"type\\":\\"Attribute\\",\\"name\\":\\"lang\\",\\"value\\":[{\\"start\\":153,\\"end\\":157,\\"type\\":\\"Text\\",\\"raw\\":\\"scss\\",\\"data\\":\\"scss\\"}]}],\\"children\\":[{\\"type\\":\\"Rule\\",\\"prelude\\":{\\"type\\":\\"SelectorList\\",\\"children\\":[{\\"type\\":\\"Selector\\",\\"children\\":[{\\"type\\":\\"TypeSelector\\",\\"name\\":\\"button\\",\\"start\\":159,\\"end\\":165}],\\"start\\":159,\\"end\\":165}],\\"start\\":159,\\"end\\":165},\\"block\\":{\\"type\\":\\"Block\\",\\"children\\":[{\\"type\\":\\"Declaration\\",\\"important\\":false,\\"property\\":\\"color\\",\\"value\\":{\\"type\\":\\"Value\\",\\"children\\":[{\\"type\\":\\"Hash\\",\\"value\\":\\"000099\\",\\"start\\":177,\\"end\\":184}],\\"start\\":177,\\"end\\":184},\\"start\\":170,\\"end\\":184}],\\"start\\":166,\\"end\\":187},\\"start\\":159,\\"end\\":187}],\\"content\\":{\\"start\\":159,\\"end\\":187,\\"styles\\":\\"button {\\\\n color: #000099;\\\\n}\\"}},\\"instance\\":{\\"type\\":\\"Script\\",\\"start\\":0,\\"end\\":60,\\"context\\":\\"default\\",\\"content\\":{\\"type\\":\\"Program\\",\\"start\\":18,\\"end\\":51,\\"loc\\":{\\"start\\":{\\"line\\":1,\\"column\\":0},\\"end\\":{\\"line\\":3,\\"column\\":0}},\\"body\\":[{\\"type\\":\\"ExportNamedDeclaration\\",\\"start\\":18,\\"end\\":34,\\"loc\\":{\\"start\\":{\\"line\\":1,\\"column\\":18},\\"end\\":{\\"line\\":1,\\"column\\":34}},\\"declaration\\":{\\"type\\":\\"VariableDeclaration\\",\\"start\\":25,\\"end\\":34,\\"loc\\":{\\"start\\":{\\"line\\":1,\\"column\\":25},\\"end\\":{\\"line\\":1,\\"column\\":34}},\\"declarations\\":[{\\"type\\":\\"VariableDeclarator\\",\\"start\\":29,\\"end\\":33,\\"loc\\":{\\"start\\":{\\"line\\":1,\\"column\\":29},\\"end\\":{\\"line\\":1,\\"column\\":33}},\\"id\\":{\\"type\\":\\"Identifier\\",\\"start\\":29,\\"end\\":33,\\"loc\\":{\\"start\\":{\\"line\\":1,\\"column\\":29},\\"end\\":{\\"line\\":1,\\"column\\":33}},\\"name\\":\\"name\\"},\\"init\\":null}],\\"kind\\":\\"let\\"},\\"specifiers\\":[],\\"source\\":null},{\\"type\\":\\"VariableDeclaration\\",\\"start\\":35,\\"end\\":50,\\"loc\\":{\\"start\\":{\\"line\\":2,\\"column\\":0},\\"end\\":{\\"line\\":2,\\"column\\":15}},\\"declarations\\":[{\\"type\\":\\"VariableDeclarator\\",\\"start\\":39,\\"end\\":49,\\"loc\\":{\\"start\\":{\\"line\\":2,\\"column\\":4},\\"end\\":{\\"line\\":2,\\"column\\":14}},\\"id\\":{\\"type\\":\\"Identifier\\",\\"start\\":39,\\"end\\":45,\\"loc\\":{\\"start\\":{\\"line\\":2,\\"column\\":4},\\"end\\":{\\"line\\":2,\\"column\\":10}},\\"name\\":\\"clicks\\"},\\"init\\":{\\"type\\":\\"Literal\\",\\"start\\":48,\\"end\\":49,\\"loc\\":{\\"start\\":{\\"line\\":2,\\"column\\":13},\\"end\\":{\\"line\\":2,\\"column\\":14}},\\"value\\":0,\\"raw\\":\\"0\\"}}],\\"kind\\":\\"let\\"}],\\"sourceType\\":\\"module\\"}}} +export const css={\\"code\\":\\"button.svelte-d8vj6a{color:#000099}\\",\\"map\\":null} +export const dependencies=[] +export const js={\\"code\\":\\"/* src/Dummy.svelte generated by Svelte vXXX */\\\\nimport {\\\\n\\\\tSvelteComponent as SvelteComponent$,\\\\n\\\\tappend as append$,\\\\n\\\\tattr as attr$,\\\\n\\\\tdetach as detach$,\\\\n\\\\telement as element$,\\\\n\\\\tinit as init$,\\\\n\\\\tinsert as insert$,\\\\n\\\\tlisten as listen$,\\\\n\\\\tnoop as noop$,\\\\n\\\\tsafe_not_equal as safe_not_equal$,\\\\n\\\\tset_data as set_data$,\\\\n\\\\ttext as text$\\\\n} from \\\\\\"svelte/internal\\\\\\";\\\\n\\\\nfunction create_fragment(ctx) {\\\\n\\\\tlet button$;\\\\n\\\\tlet t0$;\\\\n\\\\tlet t1$;\\\\n\\\\tlet t2$;\\\\n\\\\tlet mounted;\\\\n\\\\tlet dispose;\\\\n\\\\n\\\\treturn {\\\\n\\\\t\\\\tc() {\\\\n\\\\t\\\\t\\\\tbutton$ = element$(\\\\\\"button\\\\\\");\\\\n\\\\t\\\\t\\\\tt0$ = text$(/*name*/ ctx[0]);\\\\n\\\\t\\\\t\\\\tt1$ = text$(\\\\\\" clicks: \\\\\\");\\\\n\\\\t\\\\t\\\\tt2$ = text$(/*clicks*/ ctx[1]);\\\\n\\\\t\\\\t\\\\tattr$(button$, \\\\\\"class\\\\\\", \\\\\\"svelte-d8vj6a\\\\\\");\\\\n\\\\t\\\\t},\\\\n\\\\t\\\\tm(target, anchor) {\\\\n\\\\t\\\\t\\\\tinsert$(target, button$, anchor);\\\\n\\\\t\\\\t\\\\tappend$(button$, t0$);\\\\n\\\\t\\\\t\\\\tappend$(button$, t1$);\\\\n\\\\t\\\\t\\\\tappend$(button$, t2$);\\\\n\\\\n\\\\t\\\\t\\\\tif (!mounted) {\\\\n\\\\t\\\\t\\\\t\\\\tdispose = listen$(button$, \\\\\\"click\\\\\\", /*click_handler$*/ ctx[2]);\\\\n\\\\t\\\\t\\\\t\\\\tmounted = true;\\\\n\\\\t\\\\t\\\\t}\\\\n\\\\t\\\\t},\\\\n\\\\t\\\\tp(ctx, [dirty]) {\\\\n\\\\t\\\\t\\\\tif (dirty & /*name*/ 1) set_data$(t0$, /*name*/ ctx[0]);\\\\n\\\\t\\\\t\\\\tif (dirty & /*clicks*/ 2) set_data$(t2$, /*clicks*/ ctx[1]);\\\\n\\\\t\\\\t},\\\\n\\\\t\\\\ti: noop$,\\\\n\\\\t\\\\to: noop$,\\\\n\\\\t\\\\td(detaching) {\\\\n\\\\t\\\\t\\\\tif (detaching) detach$(button$);\\\\n\\\\t\\\\t\\\\tmounted = false;\\\\n\\\\t\\\\t\\\\tdispose();\\\\n\\\\t\\\\t}\\\\n\\\\t};\\\\n}\\\\n\\\\nfunction instance$($$self, $$props, $$invalidate) {\\\\n\\\\tlet { name } = $$props;\\\\n\\\\tlet clicks = 0;\\\\n\\\\n\\\\tconst click_handler$ = () => {\\\\n\\\\t\\\\t$$invalidate(1, clicks++, clicks);\\\\n\\\\t};\\\\n\\\\n\\\\t$$self.$$set = $$props => {\\\\n\\\\t\\\\tif ('name' in $$props) $$invalidate(0, name = $$props.name);\\\\n\\\\t};\\\\n\\\\n\\\\treturn [name, clicks, click_handler$];\\\\n}\\\\n\\\\nclass Dummy$ extends SvelteComponent$ {\\\\n\\\\tconstructor(options) {\\\\n\\\\t\\\\tsuper();\\\\n\\\\t\\\\tinit$(this, options, instance$, create_fragment, safe_not_equal$, { name: 0 });\\\\n\\\\t}\\\\n}\\\\n\\\\nexport default Dummy$;\\",\\"map\\":null,\\"dependencies\\":[]} +export const lang=\\"ts\\" +export const normalizedFilename=\\"/src/Dummy.svelte\\" +export const preprocessed={\\"code\\":\\"\\\\n\\\\n {\\\\n\\\\t\\\\tclicks++;\\\\n\\\\t}}>{name} clicks: {clicks}\\\\n\\\\n\\\\n\\",\\"dependencies\\":[],\\"map\\":{\\"version\\":3,\\"mappings\\":\\"AAAA,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CCCT,MAAA,CAAA,GAAA,CAAI,IAAA;AACX,GAAA,CAAI,MAAA,CAAA,CAAA,CAAS,CAAA;ADCd,CAAC,CAAC,MAAM;;AAER,CAAC;AACD,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjB,EAAE,MAAM,CAAC,CAAC;AACV,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAC7B;;AAEA,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;;CAKlB,CAAC,CAAC,KAAK;\\",\\"names\\":[],\\"sources\\":[\\"Dummy.svelte\\",\\"Dummy.svelte\\"]}} +export const source=\\"\\\\n\\\\n {\\\\n\\\\t\\\\tclicks++;\\\\n\\\\t}}>{name} clicks: {clicks}\\\\n\\\\n\\\\n\\" +export const ssr=false +export const stats={\\"timings\\":{\\"total\\":0.123456789,\\"parse\\":{\\"total\\":0.123456789},\\"create component\\":{\\"total\\":0.123456789}}} +export const vars=[{\\"name\\":\\"name\\",\\"export_name\\":\\"name\\",\\"injected\\":false,\\"module\\":false,\\"mutated\\":false,\\"reassigned\\":false,\\"referenced\\":true,\\"writable\\":true,\\"referenced_from_script\\":false},{\\"name\\":\\"clicks\\",\\"export_name\\":null,\\"injected\\":false,\\"module\\":false,\\"mutated\\":false,\\"reassigned\\":true,\\"referenced\\":true,\\"writable\\":true,\\"referenced_from_script\\":false}] +export const warnings=[] +" +`; + +exports[`raw > mixed exports > Dummy.svelte?raw&svelte&type=preprocessed 1`] = ` +"export const code=\\"\\\\n\\\\n {\\\\n\\\\t\\\\tclicks++;\\\\n\\\\t}}>{name} clicks: {clicks}\\\\n\\\\n\\\\n\\" +export const dependencies=[] +export const map={\\"version\\":3,\\"mappings\\":\\"AAAA,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CCCT,MAAA,CAAA,GAAA,CAAI,IAAA;AACX,GAAA,CAAI,MAAA,CAAA,CAAA,CAAS,CAAA;ADCd,CAAC,CAAC,MAAM;;AAER,CAAC;AACD,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjB,EAAE,MAAM,CAAC,CAAC;AACV,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAC7B;;AAEA,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;;CAKlB,CAAC,CAAC,KAAK;\\",\\"names\\":[],\\"sources\\":[\\"Dummy.svelte\\",\\"Dummy.svelte\\"]} +export default code +" +`; + +exports[`raw > mixed exports > Dummy.svelte?raw&svelte&type=script 1`] = ` +"export const code=\\"/* src/Dummy.svelte generated by Svelte vXXX */\\\\nimport {\\\\n\\\\tSvelteComponent as SvelteComponent$,\\\\n\\\\tappend as append$,\\\\n\\\\tattr as attr$,\\\\n\\\\tdetach as detach$,\\\\n\\\\telement as element$,\\\\n\\\\tinit as init$,\\\\n\\\\tinsert as insert$,\\\\n\\\\tlisten as listen$,\\\\n\\\\tnoop as noop$,\\\\n\\\\tsafe_not_equal as safe_not_equal$,\\\\n\\\\tset_data as set_data$,\\\\n\\\\ttext as text$\\\\n} from \\\\\\"svelte/internal\\\\\\";\\\\n\\\\nfunction create_fragment(ctx) {\\\\n\\\\tlet button$;\\\\n\\\\tlet t0$;\\\\n\\\\tlet t1$;\\\\n\\\\tlet t2$;\\\\n\\\\tlet mounted;\\\\n\\\\tlet dispose;\\\\n\\\\n\\\\treturn {\\\\n\\\\t\\\\tc() {\\\\n\\\\t\\\\t\\\\tbutton$ = element$(\\\\\\"button\\\\\\");\\\\n\\\\t\\\\t\\\\tt0$ = text$(/*name*/ ctx[0]);\\\\n\\\\t\\\\t\\\\tt1$ = text$(\\\\\\" clicks: \\\\\\");\\\\n\\\\t\\\\t\\\\tt2$ = text$(/*clicks*/ ctx[1]);\\\\n\\\\t\\\\t\\\\tattr$(button$, \\\\\\"class\\\\\\", \\\\\\"svelte-d8vj6a\\\\\\");\\\\n\\\\t\\\\t},\\\\n\\\\t\\\\tm(target, anchor) {\\\\n\\\\t\\\\t\\\\tinsert$(target, button$, anchor);\\\\n\\\\t\\\\t\\\\tappend$(button$, t0$);\\\\n\\\\t\\\\t\\\\tappend$(button$, t1$);\\\\n\\\\t\\\\t\\\\tappend$(button$, t2$);\\\\n\\\\n\\\\t\\\\t\\\\tif (!mounted) {\\\\n\\\\t\\\\t\\\\t\\\\tdispose = listen$(button$, \\\\\\"click\\\\\\", /*click_handler$*/ ctx[2]);\\\\n\\\\t\\\\t\\\\t\\\\tmounted = true;\\\\n\\\\t\\\\t\\\\t}\\\\n\\\\t\\\\t},\\\\n\\\\t\\\\tp(ctx, [dirty]) {\\\\n\\\\t\\\\t\\\\tif (dirty & /*name*/ 1) set_data$(t0$, /*name*/ ctx[0]);\\\\n\\\\t\\\\t\\\\tif (dirty & /*clicks*/ 2) set_data$(t2$, /*clicks*/ ctx[1]);\\\\n\\\\t\\\\t},\\\\n\\\\t\\\\ti: noop$,\\\\n\\\\t\\\\to: noop$,\\\\n\\\\t\\\\td(detaching) {\\\\n\\\\t\\\\t\\\\tif (detaching) detach$(button$);\\\\n\\\\t\\\\t\\\\tmounted = false;\\\\n\\\\t\\\\t\\\\tdispose();\\\\n\\\\t\\\\t}\\\\n\\\\t};\\\\n}\\\\n\\\\nfunction instance$($$self, $$props, $$invalidate) {\\\\n\\\\tlet { name } = $$props;\\\\n\\\\tlet clicks = 0;\\\\n\\\\n\\\\tconst click_handler$ = () => {\\\\n\\\\t\\\\t$$invalidate(1, clicks++, clicks);\\\\n\\\\t};\\\\n\\\\n\\\\t$$self.$$set = $$props => {\\\\n\\\\t\\\\tif ('name' in $$props) $$invalidate(0, name = $$props.name);\\\\n\\\\t};\\\\n\\\\n\\\\treturn [name, clicks, click_handler$];\\\\n}\\\\n\\\\nclass Dummy$ extends SvelteComponent$ {\\\\n\\\\tconstructor(options) {\\\\n\\\\t\\\\tsuper();\\\\n\\\\t\\\\tinit$(this, options, instance$, create_fragment, safe_not_equal$, { name: 0 });\\\\n\\\\t}\\\\n}\\\\n\\\\nexport default Dummy$;\\" +export const dependencies=[] +export const map=null +export default code +" +`; + +exports[`raw > mixed exports > Dummy.svelte?raw&svelte&type=style 1`] = ` +"export const code=\\"button.svelte-d8vj6a{color:#000099}\\" +export const map=null +export default code +" +`; + +exports[`ssrLoadModule > ?raw 1`] = ` +" + + + + +" +`; + +exports[`ssrLoadModule > ?raw&svelte&type=preprocessed 1`] = ` +" + + + + +" +`; + +exports[`ssrLoadModule > ?raw&svelte&type=script 1`] = ` +"/* src/Dummy.svelte generated by Svelte vXXX */ +import { + SvelteComponent as SvelteComponent$, + append as append$, + attr as attr$, + detach as detach$, + element as element$, + init as init$, + insert as insert$, + listen as listen$, + noop as noop$, + safe_not_equal as safe_not_equal$, + set_data as set_data$, + text as text$ +} from \\"svelte/internal\\"; + +function create_fragment(ctx) { + let button$; + let t0$; + let t1$; + let t2$; + let mounted; + let dispose; + + return { + c() { + button$ = element$(\\"button\\"); + t0$ = text$(/*name*/ ctx[0]); + t1$ = text$(\\" clicks: \\"); + t2$ = text$(/*clicks*/ ctx[1]); + attr$(button$, \\"class\\", \\"svelte-d8vj6a\\"); + }, + m(target, anchor) { + insert$(target, button$, anchor); + append$(button$, t0$); + append$(button$, t1$); + append$(button$, t2$); + + if (!mounted) { + dispose = listen$(button$, \\"click\\", /*click_handler$*/ ctx[2]); + mounted = true; + } + }, + p(ctx, [dirty]) { + if (dirty & /*name*/ 1) set_data$(t0$, /*name*/ ctx[0]); + if (dirty & /*clicks*/ 2) set_data$(t2$, /*clicks*/ ctx[1]); + }, + i: noop$, + o: noop$, + d(detaching) { + if (detaching) detach$(button$); + mounted = false; + dispose(); + } + }; +} + +function instance$($$self, $$props, $$invalidate) { + let { name } = $$props; + let clicks = 0; + + const click_handler$ = () => { + $$invalidate(1, clicks++, clicks); + }; + + $$self.$$set = $$props => { + if ('name' in $$props) $$invalidate(0, name = $$props.name); + }; + + return [name, clicks, click_handler$]; +} + +class Dummy$ extends SvelteComponent$ { + constructor(options) { + super(); + init$(this, options, instance$, create_fragment, safe_not_equal$, { name: 0 }); + } +} + +export default Dummy$;" +`; + +exports[`ssrLoadModule > ?raw&svelte&type=script&compilerOptions={"customElement":true} 1`] = ` +"/* src/Dummy.svelte generated by Svelte vXXX */ +import { + SvelteElement as SvelteElement$, + append as append$, + attribute_to_object as attribute_to_object$, + detach as detach$, + element as element$, + flush as flush$, + init as init$, + insert as insert$, + listen as listen$, + noop as noop$, + safe_not_equal as safe_not_equal$, + set_data as set_data$, + text as text$ +} from \\"svelte/internal\\"; + +function create_fragment(ctx) { + let button$; + let t0$; + let t1$; + let t2$; + let mounted; + let dispose; + + return { + c() { + button$ = element$(\\"button\\"); + t0$ = text$(/*name*/ ctx[0]); + t1$ = text$(\\" clicks: \\"); + t2$ = text$(/*clicks*/ ctx[1]); + this.c = noop$; + }, + m(target, anchor) { + insert$(target, button$, anchor); + append$(button$, t0$); + append$(button$, t1$); + append$(button$, t2$); + + if (!mounted) { + dispose = listen$(button$, \\"click\\", /*click_handler$*/ ctx[2]); + mounted = true; + } + }, + p(ctx, [dirty]) { + if (dirty & /*name*/ 1) set_data$(t0$, /*name*/ ctx[0]); + if (dirty & /*clicks*/ 2) set_data$(t2$, /*clicks*/ ctx[1]); + }, + i: noop$, + o: noop$, + d(detaching) { + if (detaching) detach$(button$); + mounted = false; + dispose(); + } + }; +} + +function instance$($$self, $$props, $$invalidate) { + let { name } = $$props; + let clicks = 0; + + const click_handler$ = () => { + $$invalidate(1, clicks++, clicks); + }; + + $$self.$$set = $$props => { + if ('name' in $$props) $$invalidate(0, name = $$props.name); + }; + + return [name, clicks, click_handler$]; +} + +class Dummy$ extends SvelteElement$ { + constructor(options) { + super(); + this.shadowRoot.innerHTML = \`\`; + + init$( + this, + { + target: this.shadowRoot, + props: attribute_to_object$(this.attributes), + customElement: true + }, + instance$, + create_fragment, + safe_not_equal$, + { name: 0 }, + null + ); + + if (options) { + if (options.target) { + insert$(options.target, this, options.anchor); + } + + if (options.props) { + this.$set(options.props); + flush$(); + } + } + } + + static get observedAttributes() { + return [\\"name\\"]; + } + + get name() { + return this.$$.ctx[0]; + } + + set name(name) { + this.$$set({ name }); + flush$(); + } +} + +export default Dummy$;" +`; + +exports[`ssrLoadModule > ?raw&svelte&type=style 1`] = `"button.svelte-d8vj6a{color:#000099}"`; diff --git a/packages/e2e-tests/import-queries/__tests__/import-queries.spec.ts b/packages/e2e-tests/import-queries/__tests__/import-queries.spec.ts new file mode 100644 index 000000000..27f7c8638 --- /dev/null +++ b/packages/e2e-tests/import-queries/__tests__/import-queries.spec.ts @@ -0,0 +1,164 @@ +import { browserLogs, fetchFromPage, getText, isBuild, testDir } from '~utils'; +import { createServer, ViteDevServer } from 'vite'; + +function normalizeSnapshot(result: string) { + // during dev, the import is rewritten but can vary on the v= hash. replace with stable short import + return result + .replace(/\.js\?v=[0-9a-f]{8}/g, '.js?v=XXX') // vite import analysis import rewrite version query + .replace(/generated by Svelte v\d\.\d+\.\d+/g, 'generated by Svelte vXXX') // compiler version comment + .replace(/"total": *\d+\.\d+/g, '"total":0.123456789'); // svelte compile stats +} + +describe('raw', () => { + test('does not have failed requests', async () => { + browserLogs.forEach((msg) => { + expect(msg).not.toMatch('404'); + }); + }); + + test('Dummy.svelte', async () => { + expect(await getText('#component button')).toBe('dummy clicks: 0'); + }); + + test('Dummy.svelte?raw', async () => { + const result = await getText('#raw'); + expect(result).toMatchSnapshot(); + }); + + test('Dummy.svelte?raw&svelte&type=preprocessed', async () => { + const result = await getText('#preprocessed'); + expect(result).toMatchSnapshot(); + }); + + test(`Dummy.svelte?raw&svelte&type=script`, async () => { + const result = await getText('#script'); + expect(normalizeSnapshot(result)).toMatchSnapshot(); + }); + + test('Dummy.svelte?raw&svelte&type=script&compilerOptions={"customElement":true}', async () => { + const result = await getText('#wcScript'); + expect(normalizeSnapshot(result)).toMatchSnapshot(); + }); + + test('Dummy.svelte?raw&svelte&type=style', async () => { + const result = await getText('#style'); + expect(result).toMatchSnapshot(); + }); + + test('Dummy.svelte?raw&svelte&type=all&sourcemap', async () => { + const result = await getText('#all'); + expect(normalizeSnapshot(result)).toMatchSnapshot(); + }); + + describe.runIf(!isBuild)('mixed exports', () => { + test('Dummy.svelte?raw&svelte&type=preprocessed', async () => { + const module = await fetchFromPage('src/Dummy.svelte?raw&svelte&type=preprocessed').then( + (res) => res.text() + ); + expect(normalizeSnapshot(module)).toMatchSnapshot(); + }); + test('Dummy.svelte?raw&svelte&type=style', async () => { + const module = await fetchFromPage('src/Dummy.svelte?raw&svelte&type=style').then((res) => + res.text() + ); + expect(normalizeSnapshot(module)).toMatchSnapshot(); + }); + test('Dummy.svelte?raw&svelte&type=script', async () => { + const module = await fetchFromPage('src/Dummy.svelte?raw&svelte&type=script').then((res) => + res.text() + ); + expect(normalizeSnapshot(module)).toMatchSnapshot(); + }); + test('Dummy.svelte?raw&svelte&type=all', async () => { + const module = await fetchFromPage('src/Dummy.svelte?raw&svelte&type=all').then((res) => + res.text() + ); + expect(normalizeSnapshot(module)).toMatchSnapshot(); + }); + }); +}); + +// vitest prints a warning about obsolete snapshots during build tests, ignore it, they are used in dev tests. +// always regenerate snapshots with `pnpm test:serve import-queries -u` and check the diffs if they are correct +describe.runIf(isBuild)('snapshots not obsolete warning', async () => { + afterAll(() => { + console.log( + 'Ignore the obsolete snapshot warnings for ssrLoadModule snapshots from vitest during test:build, they are used in test:serve' + ); + }); + test('suite not empty', () => { + expect(true).toBe(true); + }); +}); + +describe.runIf(!isBuild)('direct', () => { + test('Dummy.svelte?direct&svelte&type=style&sourcemap&lang.css', async () => { + const response = await fetchFromPage( + 'src/Dummy.svelte?direct&svelte&type=style&sourcemap&lang.css', + { + headers: { Accept: 'text/css' } + } + ); + expect(response.ok).toBe(true); + expect(response.headers.get('Content-Type')).toBe('text/css'); + const css = await response.text(); + expect(css).toMatchSnapshot(); + }); + test('Dummy.svelte?direct&svelte&type=script&sourcemap&lang.js', async () => { + const response = await fetchFromPage( + 'src/Dummy.svelte?direct&svelte&type=script&sourcemap&lang.js', + { + headers: { Accept: 'application/javascript' } + } + ); + expect(response.ok).toBe(true); + expect(response.headers.get('Content-Type')).toBe('application/javascript'); + const js = await response.text(); + expect(normalizeSnapshot(js)).toMatchSnapshot(); + }); +}); + +describe.runIf(!isBuild)('ssrLoadModule', () => { + let vite: ViteDevServer; + let ssrLoadDummy; + beforeAll(async () => { + vite = await createServer({ + root: testDir + '/', + appType: 'custom', + server: { middlewareMode: true, hmr: false } + }); + // needed to init plugins + await vite.pluginContainer.buildStart({}); + ssrLoadDummy = async (query) => + vite + .ssrLoadModule('./src/Dummy.svelte' + query, { fixStacktrace: true }) + .then((m) => m.default?.code ?? m.default); + }); + afterAll(async () => { + await vite.close(); + vite = null; + ssrLoadDummy = null; + }); + test('?raw', async () => { + const result = await ssrLoadDummy('?raw'); + expect(result).toMatchSnapshot(); + }); + test('?raw&svelte&type=preprocessed', async () => { + const result = await ssrLoadDummy('?raw&svelte&type=preprocessed'); + expect(result).toMatchSnapshot(); + }); + test('?raw&svelte&type=script', async () => { + const result = await ssrLoadDummy('?raw&svelte&type=script'); + expect(normalizeSnapshot(result)).toMatchSnapshot(); + }); + test('?raw&svelte&type=script&compilerOptions={"customElement":true}', async () => { + const result = await ssrLoadDummy( + '?raw&svelte&type=script&compilerOptions={"customElement":true}' + ); + expect(normalizeSnapshot(result)).toMatchSnapshot(); + }); + test('?raw&svelte&type=style', async () => { + const result = await ssrLoadDummy('?raw&svelte&type=style'); + expect(result).toMatchSnapshot(); + }); +}); diff --git a/packages/e2e-tests/import-queries/index.html b/packages/e2e-tests/import-queries/index.html new file mode 100644 index 000000000..c4b05496b --- /dev/null +++ b/packages/e2e-tests/import-queries/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite + Svelte + + +
+ + + diff --git a/packages/e2e-tests/import-queries/package.json b/packages/e2e-tests/import-queries/package.json new file mode 100644 index 000000000..3dde129dc --- /dev/null +++ b/packages/e2e-tests/import-queries/package.json @@ -0,0 +1,17 @@ +{ + "name": "e2e-tests-import-queries", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite --force", + "build": "vite build", + "preview": "vite preview" + }, + "devDependencies": { + "@sveltejs/vite-plugin-svelte": "workspace:*", + "sass": "^1.56.1", + "svelte": "^3.53.1", + "vite": "^3.2.3" + } +} diff --git a/packages/e2e-tests/import-queries/public/favicon.png b/packages/e2e-tests/import-queries/public/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..7e6f5eb5a2f1f1c882d265cf479de25caa925645 GIT binary patch literal 3127 zcmV-749N3|P)i z7)}s4L53SJCkR}iVi00SFk;`MXX*#X*kkwKs@nFGS}c;=?XFjU|G$3t^5sjIVS2G+ zw)WGF83CpoGXhLGW(1gW%uV|X7>1P6VhCX=Ux)Lb!*DZ%@I3!{Gsf7d?gtIQ%nQiK z3%(LUSkBji;C5Rfgd6$VsF@H`Pk@xtY6t<>FNR-pD}=C~$?)9pdm3XZ36N5PNWYjb z$xd$yNQR9N!dfj-Vd@BwQo^FIIWPPmT&sZyQ$v81(sCBV=PGy{0wltEjB%~h157*t zvbe_!{=I_783x!0t1-r#-d{Y?ae$Q4N_Nd^Ui^@y(%)Gjou6y<3^XJdu{rmUf-Me?)zZ>9OR&6U5H*cK; z$gUlB{g0O4gN0sLSO|Of?hU(l?;h(jA3uH!Z{EBKuV23ouU@^Y6#%v+QG;>e*E}%?wlu-NT4DG zs)z)7WbLr)vGAu(ohrKc^em@OpO&f~6_>E61n_e0_V3@{U3^O;j{`^mNCJUj_>;7v zsMs6Hu3g7+@v+lSo;=yTYFqq}jZmQ-BK8K{C4kqi_i*jBaQE(Au0607V-zKeT;EPg zX(`vrn=L+e74+-Tqeok@_`tDa$G9I|$nTU5H*2V8@y()n*zqM?J1G!-1aX;CfDC9B zTnJ#j_%*n8Qb1)re*Bno7g0RG{Eb;IK14irJYJp$5Z6ac9~b_P?+5t~95~SRG$g?1 znFJ7p$xV&GZ18m~79TGRdfsc-BcX$9yXTR*n)mPD@1~O(_?cT$ZvFPucRmGlq&se0 zKrcUf^k}4hM*biEJOWKzz!qQe;CB_ZtSOO9Owg#lZAc=s65^rb{fZe(TYu_rk!wKkEf}RIt=#Om( zR8mN`DM<^xj~59euMMspBolVN zAPTr8sSDI104orIAdmL$uOXn*6hga1G+0WD0E?UtabxC#VC~vf3|10|phW;yQ3CY8 z2CM=)ErF;xq-YJ5G|um}>*1#E+O_Mu|Nr#qQ&G1P-NMq@f?@*XUcSbV?tX=)ilM-Q zBZP|!Bpv0V;#ojKcpc7$=eqO;#Uy~#?^kNI{vSZfLx&DEt~LTmaKWXcx=joubklI<*Aw z>LtMaQ7DR<1I2LkWvwyu#Rwn~;ezT}_g(@5l3h?W%-a86Y-t#O1PubP+z<%?V5D(U zy57A6{h+{?kOZp7&WKZR+=sznMJ}+Dnpo=C_0%R_x_t~J5T?E_{+))l5v1%52>)d-`iiZyx|5!%M2Fb2dU zW3~MwwpEH9Rhue+k$UIOoo($Ds!NbOyMR36fRHu;*15(YcA7siIZk#%JWz>P!qX1?IUojG&nKR>^gArBt2 zit(ETyZ=@V&7mv_Fi4bABcnwP+jzQuHcfU&BrAV91u-rFvEi7y-KnWsvHH=d2 zgAk(GKm_S8RcTJ>2N3~&Hbwp{Z3NF_Xeh}g4Eke)V&dY{W(3&b1j9t4yK_aYJisZZ{1rcU5- z;eD>K;ndPq&B-8yA_S0F!4ThA&{1{x)H<#?k9a#6Pc6L?V^s0``ynL&D;p(!Nmx`Y zFkHex{4p!Ggm^@DlehW}iHHVi}~u=$&N? z(NEBLQ#UxxAkdW>X9LnqUr#t4Lu0=9L8&o>JsqTtT5|%gb3QA~hr0pED71+iFFr)dZ=Q=E6ng{NE{Z~0)C?deO#?Aj zSDQ$z#TeC2T^|=}6GBo-&$;E{HL3!q3Z-szuf)O=G#zDjin4SSP%o%6+2IT#sLjQa ziyxFFz~LMjWY+_a5H!U6%a<=b7QVP^ z*90a62;bVq{?@)P6^DWd^Yilq4|YTV2Nw!Yu;a1lPI-sxR)rf@Fe5DhDP7FH zZZ%4S*1C30P;|O+jB!1;m|rXT90Sm5*RBbQN`PKu+hDD*S^yE(CdtSfg=z>u$cIj> z + import Dummy from './Dummy.svelte'; + import raw from './Dummy.svelte?raw'; + import preprocessed from './Dummy.svelte?raw&svelte&type=preprocessed'; + import script from './Dummy.svelte?raw&svelte&type=script'; + import wcScript from './Dummy.svelte?raw&svelte&type=script&compilerOptions={"customElement":true,"dev":false}'; + import style from './Dummy.svelte?raw&svelte&type=style'; + import * as all from './Dummy.svelte?raw&svelte&type=all&sourcemap'; + + +
+

Component

+
+

raw

+
{raw}
+

preprocessed

+
{preprocessed}
+

script

+
{script}
+

web component script

+
{wcScript}
+

style

+
{style}
+

all

+
{JSON.stringify(all, null, 2)}
+
diff --git a/packages/e2e-tests/import-queries/src/Dummy.svelte b/packages/e2e-tests/import-queries/src/Dummy.svelte new file mode 100644 index 000000000..21db6c29d --- /dev/null +++ b/packages/e2e-tests/import-queries/src/Dummy.svelte @@ -0,0 +1,17 @@ + + + + + diff --git a/packages/e2e-tests/import-queries/src/main.js b/packages/e2e-tests/import-queries/src/main.js new file mode 100644 index 000000000..2c27a2579 --- /dev/null +++ b/packages/e2e-tests/import-queries/src/main.js @@ -0,0 +1,7 @@ +import App from './App.svelte'; + +const app = new App({ + target: document.body +}); + +export default app; diff --git a/packages/e2e-tests/import-queries/src/vite-env.d.ts b/packages/e2e-tests/import-queries/src/vite-env.d.ts new file mode 100644 index 000000000..4078e7476 --- /dev/null +++ b/packages/e2e-tests/import-queries/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/packages/e2e-tests/import-queries/svelte.config.js b/packages/e2e-tests/import-queries/svelte.config.js new file mode 100644 index 000000000..f3a4f4ccb --- /dev/null +++ b/packages/e2e-tests/import-queries/svelte.config.js @@ -0,0 +1,12 @@ +export default { + vitePlugin: { + experimental: { + useVitePreprocess: true + } + }, + onwarn(warning, defaultHandler) { + // import query test generates one of these + if (warning.code === 'custom-element-no-tag') return; + defaultHandler(warning); + } +}; diff --git a/packages/e2e-tests/import-queries/vite.config.js b/packages/e2e-tests/import-queries/vite.config.js new file mode 100644 index 000000000..24823c71d --- /dev/null +++ b/packages/e2e-tests/import-queries/vite.config.js @@ -0,0 +1,28 @@ +import { defineConfig } from 'vite'; +import { svelte } from '@sveltejs/vite-plugin-svelte'; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte()], + optimizeDeps: { + exclude: [ + // TODO this must be excluded because nested has an scss dep that prebundle can't handle! + // figure out how to exclude it automatically or at least tell the user about it in a more friendly way + 'e2e-test-dep-scss-only', + 'e2e-test-dep-svelte-hybrid' + ] + }, + build: { + // make build faster by skipping transforms and minification + target: 'esnext', + minify: false + }, + server: { + watch: { + // During tests we edit the files too fast and sometimes chokidar + // misses change events, so enforce polling for consistency + usePolling: true, + interval: 100 + } + } +}); diff --git a/packages/e2e-tests/testUtils.ts b/packages/e2e-tests/testUtils.ts index a87cf517c..eea67ae6d 100644 --- a/packages/e2e-tests/testUtils.ts +++ b/packages/e2e-tests/testUtils.ts @@ -269,6 +269,10 @@ export async function fetchPageText() { } } +export async function fetchFromPage(url, init?) { + const fullUrl = page.url() + (url.startsWith('/') ? url.slice(1) : url); + return fetch(fullUrl, init); +} export function readVitePrebundleMetadata() { const metadataPaths = [ 'node_modules/.vite/_metadata.json', diff --git a/packages/vite-plugin-svelte/src/handle-hot-update.ts b/packages/vite-plugin-svelte/src/handle-hot-update.ts index 0349abfea..6f3b90ff2 100644 --- a/packages/vite-plugin-svelte/src/handle-hot-update.ts +++ b/packages/vite-plugin-svelte/src/handle-hot-update.ts @@ -20,7 +20,7 @@ export async function handleHotUpdate( log.debug(`handleHotUpdate called before initial transform for ${svelteRequest.id}`); return; } - const { read, server } = ctx; + const { read, server, modules } = ctx; const cachedJS = cache.getJS(svelteRequest); const cachedCss = cache.getCSS(svelteRequest); @@ -35,41 +35,41 @@ export async function handleHotUpdate( throw e; } - const affectedModules = new Set(); + const affectedModules = [...modules]; - const cssModule = server.moduleGraph.getModuleById(svelteRequest.cssId); - const mainModule = server.moduleGraph.getModuleById(svelteRequest.id); - const cssUpdated = cssModule && cssChanged(cachedCss, compileData.compiled.css); - if (cssUpdated) { - log.debug(`handleHotUpdate css changed for ${svelteRequest.cssId}`); - affectedModules.add(cssModule); + const cssIdx = modules.findIndex((m) => m.id === svelteRequest.cssId); + if (cssIdx > -1) { + const cssUpdated = cssChanged(cachedCss, compileData.compiled.css); + if (!cssUpdated) { + log.debug(`skipping unchanged css for ${svelteRequest.cssId}`); + affectedModules.splice(cssIdx, 1); + } } - const jsUpdated = - mainModule && jsChanged(cachedJS, compileData.compiled.js, svelteRequest.filename); - if (jsUpdated) { - log.debug(`handleHotUpdate js changed for ${svelteRequest.id}`); - affectedModules.add(mainModule); + const jsIdx = modules.findIndex((m) => m.id === svelteRequest.id); + if (jsIdx > -1) { + const jsUpdated = jsChanged(cachedJS, compileData.compiled.js, svelteRequest.filename); + if (!jsUpdated) { + log.debug(`skipping unchanged js for ${svelteRequest.id}`); + affectedModules.splice(jsIdx, 1); + // transform won't be called, log warnings here + logCompilerWarnings(svelteRequest, compileData.compiled.warnings, options); + } } - if (!jsUpdated) { - // transform won't be called, log warnings here - logCompilerWarnings(svelteRequest, compileData.compiled.warnings, options); - } - - const result = [...affectedModules].filter(Boolean) as ModuleNode[]; - // TODO is this enough? see also: https://github.com/vitejs/vite/issues/2274 - const ssrModulesToInvalidate = result.filter((m) => !!m.ssrTransformResult); + const ssrModulesToInvalidate = affectedModules.filter((m) => !!m.ssrTransformResult); if (ssrModulesToInvalidate.length > 0) { log.debug(`invalidating modules ${ssrModulesToInvalidate.map((m) => m.id).join(', ')}`); ssrModulesToInvalidate.forEach((moduleNode) => server.moduleGraph.invalidateModule(moduleNode)); } - if (result.length > 0) { + if (affectedModules.length > 0) { log.debug( - `handleHotUpdate for ${svelteRequest.id} result: ${result.map((m) => m.id).join(', ')}` + `handleHotUpdate for ${svelteRequest.id} result: ${affectedModules + .map((m) => m.id) + .join(', ')}` ); } - return result; + return affectedModules; } function cssChanged(prev?: Code, next?: Code): boolean { diff --git a/packages/vite-plugin-svelte/src/index.ts b/packages/vite-plugin-svelte/src/index.ts index df0587415..48d751b5f 100644 --- a/packages/vite-plugin-svelte/src/index.ts +++ b/packages/vite-plugin-svelte/src/index.ts @@ -4,8 +4,8 @@ import { HmrContext, ModuleNode, Plugin, ResolvedConfig, UserConfig } from 'vite import { isDepExcluded } from 'vitefu'; import { handleHotUpdate } from './handle-hot-update'; import { log, logCompilerWarnings } from './utils/log'; -import { CompileData, createCompileSvelte } from './utils/compile'; -import { buildIdParser, IdParser, SvelteRequest } from './utils/id'; +import { type CompileSvelte, createCompileSvelte } from './utils/compile'; +import { buildIdParser, IdParser } from './utils/id'; import { buildExtraViteConfig, validateInlineOptions, @@ -23,6 +23,7 @@ import { toRollupError } from './utils/error'; import { saveSvelteMetadata } from './utils/optimizer'; import { svelteInspector } from './ui/inspector/plugin'; import { VitePluginSvelteCache } from './utils/vite-plugin-svelte-cache'; +import { loadRaw } from './utils/load-raw'; interface PluginAPI { /** @@ -45,11 +46,7 @@ export function svelte(inlineOptions?: Partial): Plugin[] { let options: ResolvedOptions; let viteConfig: ResolvedConfig; /* eslint-disable no-unused-vars */ - let compileSvelte: ( - svelteRequest: SvelteRequest, - code: string, - options: Partial - ) => Promise; + let compileSvelte: CompileSvelte; /* eslint-enable no-unused-vars */ let resolvedSvelteSSR: Promise; @@ -103,23 +100,26 @@ export function svelte(inlineOptions?: Partial): Plugin[] { setupWatchers(options, cache, requestParser); }, - load(id, opts) { + async load(id, opts) { const ssr = !!opts?.ssr; const svelteRequest = requestParser(id, !!ssr); if (svelteRequest) { - const { filename, query } = svelteRequest; - // virtual css module - if (query.svelte && query.type === 'style') { - const css = cache.getCSS(svelteRequest); - if (css) { - log.debug(`load returns css for ${filename}`); - return css; + const { filename, query, raw } = svelteRequest; + if (raw) { + return loadRaw(svelteRequest, compileSvelte, options); + } else { + if (query.svelte && query.type === 'style') { + const css = cache.getCSS(svelteRequest); + if (css) { + log.debug(`load returns css for ${filename}`); + return css; + } + } + // prevent vite asset plugin from loading files as url that should be compiled in transform + if (viteConfig.assetsInclude(filename)) { + log.debug(`load returns raw content for ${filename}`); + return fs.readFileSync(filename, 'utf-8'); } - } - // prevent vite asset plugin from loading files as url that should be compiled in transform - if (viteConfig.assetsInclude(filename)) { - log.debug(`load returns raw content for ${filename}`); - return fs.readFileSync(filename, 'utf-8'); } } }, @@ -128,14 +128,12 @@ export function svelte(inlineOptions?: Partial): Plugin[] { const ssr = !!opts?.ssr; const svelteRequest = requestParser(importee, ssr); if (svelteRequest?.query.svelte) { - if (svelteRequest.query.type === 'style') { + if (svelteRequest.query.type === 'style' && !svelteRequest.raw) { // return cssId with root prefix so postcss pipeline of vite finds the directory correctly // see https://github.com/sveltejs/vite-plugin-svelte/issues/14 log.debug(`resolveId resolved virtual css module ${svelteRequest.cssId}`); return svelteRequest.cssId; } - log.debug(`resolveId resolved ${importee}`); - return importee; // query with svelte tag, an id we generated, no need for further analysis } if (ssr && importee === 'svelte') { @@ -188,7 +186,7 @@ export function svelte(inlineOptions?: Partial): Plugin[] { async transform(code, id, opts) { const ssr = !!opts?.ssr; const svelteRequest = requestParser(id, ssr); - if (!svelteRequest || svelteRequest.query.svelte) { + if (!svelteRequest || svelteRequest.query.type === 'style' || svelteRequest.raw) { return; } let compileData; diff --git a/packages/vite-plugin-svelte/src/utils/compile.ts b/packages/vite-plugin-svelte/src/utils/compile.ts index f169c31d3..4f0e9c244 100644 --- a/packages/vite-plugin-svelte/src/utils/compile.ts +++ b/packages/vite-plugin-svelte/src/utils/compile.ts @@ -6,17 +6,41 @@ import { SvelteRequest } from './id'; import { safeBase64Hash } from './hash'; import { log } from './log'; import { StatCollection } from './vite-plugin-svelte-stats'; +//eslint-disable-next-line node/no-missing-import +import type { Processed } from 'svelte/types/compiler/preprocess'; +import { createInjectScopeEverythingRulePreprocessorGroup } from './preprocess'; +import path from 'path'; const scriptLangRE = /