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: [
{