diff --git a/.changeset/yellow-squids-explain.md b/.changeset/yellow-squids-explain.md new file mode 100644 index 000000000000..68726741887c --- /dev/null +++ b/.changeset/yellow-squids-explain.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +feat: add version info to `window`. You can opt out by setting `discloseVersion` to `false` in the compiler options diff --git a/packages/playground/src/App.svelte b/packages/playground/src/App.svelte index ab87de6d9679..b3c16eec67ce 100644 --- a/packages/playground/src/App.svelte +++ b/packages/playground/src/App.svelte @@ -1,3 +1,7 @@ + +
Hello world!
\ No newline at end of file diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 10df08e9f1af..b778be709c22 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -56,6 +56,9 @@ "types": "./types/index.d.ts", "import": "./src/runtime/store/index.js" }, + "./internal/disclose-version": { + "import": "./src/runtime/internal/disclose-version/index.js" + }, "./transition": { "types": "./types/index.d.ts", "import": "./src/runtime/transition/index.js" diff --git a/packages/svelte/scripts/generate-version.js b/packages/svelte/scripts/generate-version.js index 9e38352be7da..3b92484610ac 100644 --- a/packages/svelte/scripts/generate-version.js +++ b/packages/svelte/scripts/generate-version.js @@ -13,5 +13,6 @@ fs.writeFileSync( * @type {string} */ export const VERSION = '${pkg.version}'; +export const PUBLIC_VERSION = '${pkg.version.split('.')[0]}'; ` ); diff --git a/packages/svelte/src/compiler/compile/index.js b/packages/svelte/src/compiler/compile/index.js index a298af458620..4271ee6c2747 100644 --- a/packages/svelte/src/compiler/compile/index.js +++ b/packages/svelte/src/compiler/compile/index.js @@ -30,7 +30,8 @@ const valid_options = [ 'loopGuardTimeout', 'preserveComments', 'preserveWhitespace', - 'cssHash' + 'cssHash', + 'discloseVersion' ]; const valid_css_values = [true, false, 'injected', 'external', 'none']; const regex_valid_identifier = /^[a-zA-Z_$][a-zA-Z_$0-9]*$/; @@ -112,6 +113,10 @@ function validate_options(options, warnings) { throw new Error(`Invalid namespace '${namespace}'`); } } + + if (options.discloseVersion == undefined) { + options.discloseVersion = true; + } } /** diff --git a/packages/svelte/src/compiler/compile/render_dom/index.js b/packages/svelte/src/compiler/compile/render_dom/index.js index 7e640ac64af5..9a11013fc90a 100644 --- a/packages/svelte/src/compiler/compile/render_dom/index.js +++ b/packages/svelte/src/compiler/compile/render_dom/index.js @@ -604,5 +604,17 @@ export default function dom(component, options) { ); } } + + if (options.discloseVersion === true) { + component.imports.unshift({ + type: 'ImportDeclaration', + specifiers: [], + source: { + type: 'Literal', + value: `${options.sveltePath ?? 'svelte'}/internal/disclose-version` + } + }); + } + return { js: flatten(body), css }; } diff --git a/packages/svelte/src/compiler/interfaces.d.ts b/packages/svelte/src/compiler/interfaces.d.ts index f99d641755c4..64be9698f5b3 100644 --- a/packages/svelte/src/compiler/interfaces.d.ts +++ b/packages/svelte/src/compiler/interfaces.d.ts @@ -344,6 +344,12 @@ export interface CompileOptions { * @default false */ preserveWhitespace?: boolean; + /** + * If `true`, exposes the Svelte major version on the global `window` object in the browser. + * + * @default true + */ + discloseVersion?: boolean; } export interface ParserOptions { diff --git a/packages/svelte/src/runtime/internal/disclose-version/index.js b/packages/svelte/src/runtime/internal/disclose-version/index.js new file mode 100644 index 000000000000..7cda592dca15 --- /dev/null +++ b/packages/svelte/src/runtime/internal/disclose-version/index.js @@ -0,0 +1,5 @@ +import { PUBLIC_VERSION } from '../../../shared/version.js'; + +if (typeof window !== 'undefined') + // @ts-ignore + (window.__svelte || (window.__svelte = { v: new Set() })).v.add(PUBLIC_VERSION); diff --git a/packages/svelte/src/shared/version.js b/packages/svelte/src/shared/version.js index 79089bf0ae49..2ccd9837c7a2 100644 --- a/packages/svelte/src/shared/version.js +++ b/packages/svelte/src/shared/version.js @@ -7,3 +7,4 @@ * @type {string} */ export const VERSION = '4.0.0-next.2'; +export const PUBLIC_VERSION = '4'; diff --git a/packages/svelte/test/helpers.js b/packages/svelte/test/helpers.js index ddc6a2818b90..596086f9860c 100644 --- a/packages/svelte/test/helpers.js +++ b/packages/svelte/test/helpers.js @@ -147,6 +147,7 @@ export function create_loader(compileOptions, cwd) { // any imported Svelte components as well. A few edge cases aren't handled but also // currently unused in the tests, for example `export * from`and live bindings. let transformed = compiled.js.code + .replace(/^import ['"]([^'"]+)['"]/gm, 'await __import("$1")') .replace( /^import \* as (\w+) from ['"]([^'"]+)['"];?/gm, 'const $1 = await __import("$2");' diff --git a/packages/svelte/test/js/js-output.test.js b/packages/svelte/test/js/js-output.test.js index 31ffe9e5eb60..95409390af52 100644 --- a/packages/svelte/test/js/js-output.test.js +++ b/packages/svelte/test/js/js-output.test.js @@ -33,7 +33,12 @@ describe('js-output', () => { let actual; try { - const options = Object.assign({}, config.options || {}); + const options = Object.assign( + { + discloseVersion: false + }, + config.options || {} + ); actual = svelte .compile(input, options) diff --git a/packages/svelte/test/runtime-browser/browser.test.js b/packages/svelte/test/runtime-browser/browser.test.js index 09eb43cf0b10..00ecaa652263 100644 --- a/packages/svelte/test/runtime-browser/browser.test.js +++ b/packages/svelte/test/runtime-browser/browser.test.js @@ -6,8 +6,7 @@ import * as svelte from 'svelte/compiler'; import { afterAll, assert, beforeAll, describe, it } from 'vitest'; import { pretty_print_browser_assertion, try_load_config } from '../helpers.js'; -const internal = path.resolve('src/runtime/internal/index.js'); -const index = path.resolve('src/runtime/index.js'); +const assert_file = path.resolve(__dirname, 'assert.js'); /** @type {import('@playwright/test').Browser} */ let browser; @@ -62,9 +61,7 @@ async function run_browser_test(dir) { alias: { __MAIN_DOT_SVELTE__: path.resolve(__dirname, 'samples', dir, 'main.svelte'), __CONFIG__: path.resolve(__dirname, 'samples', dir, '_config.js'), - 'assert.js': path.resolve(__dirname, 'assert.js'), - 'svelte/internal': internal, - svelte: index + 'assert.js': assert_file }, plugins: [ { @@ -169,9 +166,7 @@ async function run_custom_elements_test(dir) { entryPoints: [`${cwd}/test.js`], write: false, alias: { - 'assert.js': path.resolve(__dirname, 'assert.js'), - 'svelte/internal': internal, - svelte: index + 'assert.js': assert_file }, plugins: [ {