Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat] Legacy JS support (fixes #12) #6265

Open
wants to merge 125 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
125 commits
Select commit Hold shift + click to select a range
4d60069
#12: Initial commit for differential legacy builds implementation
smertelny Nov 4, 2021
b6c04c1
Extracting page data to its own variable; fixes after extraction of data
smertelny Dec 3, 2021
f18844a
(try to) merge branch 'legacy-builds' of github.com:smertelny/kit int…
Tal500 Jul 26, 2022
bd8e24a
Merge branch 'sveltejs:master' into legacy-builds
Tal500 Jul 26, 2022
2ce2297
fixing legacy chunk generation
Tal500 Aug 21, 2022
5f12ccd
Merge branch 'legacy-builds' of github.com:Tal500/kit into legacy-builds
Tal500 Aug 21, 2022
365fc7c
Merge branch 'master' into legacy-builds
Tal500 Aug 21, 2022
992bf32
carefull usage of 'composePath' for legacy
Tal500 Aug 22, 2022
ab16dc1
carefull modern code usage in kit.svelte.dev, for legacy support
Tal500 Aug 22, 2022
be104be
inject scripts on HTML to the right path and add polyfills
Tal500 Aug 22, 2022
9bfd614
install missing & reorder additional legacy polyfills
Tal500 Aug 23, 2022
bc688b0
automatic reorder of dependencies
Tal500 Aug 24, 2022
245525a
clean unused code, and zero-configuration legacy support
Tal500 Aug 24, 2022
4b2d38b
Merge branch 'master' into legacy-builds
Tal500 Aug 24, 2022
e0e11fb
remove the 'legacy' option from svelte.config.js
Tal500 Aug 24, 2022
dd99a84
uninstall terser from kit
Tal500 Aug 24, 2022
9dfaeed
undo svelte versioning
Tal500 Aug 24, 2022
906e488
update&fix? pnpm lock
Tal500 Aug 24, 2022
01a7fc5
improve disable searching on legacy browsers
Tal500 Aug 24, 2022
c67c0fd
use relative import of legacy scripts
Tal500 Aug 24, 2022
2140f56
rename ineternal property to 'legacy_assets' and support modern polyf…
Tal500 Aug 24, 2022
310a770
improve search unsupport display on legacy
Tal500 Aug 24, 2022
7d7bfde
improve legacy&pollyfills script injecting and sharing data, and fixi…
Tal500 Aug 24, 2022
0058384
formatting (and linting just works)
Tal500 Aug 25, 2022
e1faca6
better description
Tal500 Aug 25, 2022
9458254
Merge branch 'master' into legacy-builds
Tal500 Aug 25, 2022
0c75ad1
update the minimal vite version to be the one fixes #9807
Tal500 Aug 25, 2022
47280df
add a describing changeset
Tal500 Aug 25, 2022
81d1d32
add preloading to modern polyfills and make them be loaded earlier
Tal500 Aug 26, 2022
1bb0fc5
fix a bug in search box of site on modern browsers
Tal500 Aug 26, 2022
647c7fb
show better when search is unsupported in the site
Tal500 Aug 26, 2022
dadf8a9
Merge branch 'master' into legacy-builds
Tal500 Aug 28, 2022
aaf9ee4
versioning of the fork
Tal500 Aug 28, 2022
2f7852c
Merge branch 'master' into legacy-builds
Tal500 Aug 31, 2022
c0b7c0e
Merge branch 'master' into legacy-builds
Tal500 Aug 31, 2022
e498176
explicitly tell the client start script if the current mode is legacy…
Tal500 Aug 31, 2022
5530c5f
fix formatting
Tal500 Aug 31, 2022
db50689
downgrade playwright to 1.25.0 in pnpm's lock file
Tal500 Aug 31, 2022
67c98bf
Merge branch 'legacy-builds' into legacy-builds-versioning, and relea…
Tal500 Aug 31, 2022
893ec3b
make the loading script to be self-destructing
Tal500 Sep 2, 2022
fe6b184
fix formatting
Tal500 Sep 2, 2022
23e1907
restore package.json
Tal500 Sep 2, 2022
1357f13
Merge branch 'master' into legacy-builds, and install Svelte>=3.50 in…
Tal500 Sep 2, 2022
90592d4
Merge branch 'master' into legacy-builds
Tal500 Sep 4, 2022
f9c1458
use `host` header for Cross-site validation if `origin` is missing
Tal500 Sep 4, 2022
f7e82b3
add time in `load_data` on legacy, since the script tags are getting …
Tal500 Sep 4, 2022
dd60429
formatting
Tal500 Sep 4, 2022
160516d
Merge branch 'master' into legacy-builds
Tal500 Sep 5, 2022
e7682c1
fix: use `referer` instead of `host` header in cs protection, if orig…
Tal500 Sep 5, 2022
be1e182
fix linting
Tal500 Sep 5, 2022
4ba7b1c
Merge branch 'master' into legacy-builds
Tal500 Sep 7, 2022
8728261
Merge branch 'master' into legacy-builds
Tal500 Sep 10, 2022
2fad78d
use `composedPath` polyfill instead of implementing it
Tal500 Sep 10, 2022
1af12dd
Merge branch 'master' into legacy-builds.
Tal500 Sep 28, 2022
4a2dcf8
specifying script type for respecting HTML standard
Tal500 Oct 1, 2022
46cc4b1
fix credentials header issues with `whatwg-fetch` polyfill
Tal500 Oct 1, 2022
bfa6ad3
Merge branch 'master' into legacy-builds
Tal500 Oct 6, 2022
582aae0
On kit site, check the availability of Web Workers instead of Service…
Tal500 Oct 6, 2022
05b72e7
use `!!import.meta.env.LEGACY` instead of getting it as parameter to …
Tal500 Oct 6, 2022
27ec16c
Merge branch 'master' into legacy-builds
Tal500 Oct 19, 2022
cd11fbd
remove an old typing part
Tal500 Oct 19, 2022
53802e2
minor typo fixes and improving some explanations.
Tal500 Oct 22, 2022
7d32123
avoid using the problematic `var` definition for the startup code on …
Tal500 Oct 22, 2022
f9cf1fd
Merge branch 'master' into legacy-builds
Tal500 Oct 22, 2022
4420bb6
Merge branch 'master' into legacy-builds
Tal500 Nov 12, 2022
4d92610
Merge branch 'master' into legacy-builds
Tal500 Nov 14, 2022
b4aec49
fix minor issue in legacy scripting
Tal500 Nov 15, 2022
ae1f26e
Use `postcss-preset-env` in the site to fix CSS, and support more bro…
Tal500 Nov 15, 2022
b89ce2d
Merge branch 'master' into legacy-builds
Tal500 Nov 15, 2022
712ed62
Add a basic playwright test to emulate legacy browser
Tal500 Nov 15, 2022
fb1a457
cancel polyfill generation in the basic test
Tal500 Nov 15, 2022
e3d7023
add js-indicator to tests, and add a sanity check
Tal500 Nov 15, 2022
4a1ac37
format test
Tal500 Nov 15, 2022
2a609a5
add test command
Tal500 Nov 15, 2022
933f706
add back the accidently removed file
Tal500 Nov 15, 2022
3b09a89
improve tests
Tal500 Nov 15, 2022
6ce3015
register legacy tests in pnpm workspace
Tal500 Nov 15, 2022
5cdd1b0
fix flakiness of dev tests, that happen because of overriding the `da…
Tal500 Nov 16, 2022
b4baede
remove the useless `polyfills: false` config from test
Tal500 Nov 16, 2022
3882ba3
improve legacy test and a case and legacy mode
Tal500 Nov 16, 2022
f9fe5e5
fix a test issue by waiting for JS
Tal500 Nov 16, 2022
0c35ff0
fix formatting
Tal500 Nov 16, 2022
e5dcc6e
Merge master
Tal500 Dec 11, 2022
103da14
Merge branch 'master' into legacy-builds
Tal500 Dec 11, 2022
2d3739e
fix format
Tal500 Dec 11, 2022
41f379b
reset changesets of open PRs in preparation of launch
dummdidumm Dec 14, 2022
9a1f865
Merge branch 'master' into legacy-builds
Tal500 Dec 15, 2022
a5e81ca
Merge branch 'master' into legacy-builds
Tal500 Dec 22, 2022
70fca5f
fix lockfile
Tal500 Dec 22, 2022
b60be61
return&update the changeset file
Tal500 Dec 22, 2022
b291a6c
Merge branch 'master' into legacy-builds
Tal500 Jan 15, 2023
f58ca3c
move the "intersection-observer" dependency of the kit site to `devDe…
Tal500 Jan 15, 2023
841f211
put `browserslist` in `package.json` for simplicity
Tal500 Jan 15, 2023
aee9e15
fix a possible issue with `history.scrollRestoration` on legacy and u…
Tal500 Jan 15, 2023
ffbac7b
fix formatting
Tal500 Jan 15, 2023
33fef71
Merge branch 'master' into legacy-builds
Tal500 Jan 19, 2023
fc48483
clearing duplicated function defs
Tal500 Jan 19, 2023
cd9497c
Merge branch 'master' into legacy-builds
Tal500 Feb 16, 2023
ab09153
Merge branch 'master' into legacy-builds
Tal500 Feb 16, 2023
15fd8b0
fix formatting
Tal500 Feb 16, 2023
cb9f3b7
use the new automatic browserlist file reading instead of parsing it …
Tal500 Feb 16, 2023
be3a632
fix formatting
Tal500 Feb 16, 2023
5429384
Merge branch 'master' into legacy-builds
Tal500 Feb 19, 2023
896ad47
fix legacy file props in dev mode
Tal500 Feb 19, 2023
f3db95f
Merge branch 'master' into legacy-builds
Tal500 Feb 22, 2023
559f1b9
fix the root `<div>` warning
Tal500 Feb 22, 2023
2f61656
better comment about the legacy polyfills order
Tal500 Feb 22, 2023
8853947
improve legacy automated tests
Tal500 Feb 22, 2023
b688721
fix test code
Tal500 Feb 22, 2023
79cd778
Merge branch 'master' into legacy-builds
Tal500 Feb 22, 2023
0041e26
add `legacy/polyfills-loading` tests
Tal500 Feb 22, 2023
2c4d26b
fix excecution code of init in client on a special legacy situation
Tal500 Feb 22, 2023
5d920f2
better testing for legacy polyfill loading
Tal500 Feb 22, 2023
5cb0cbc
fix formatting
Tal500 Feb 22, 2023
ac11253
fix the order of kit script initialization on client
Tal500 Feb 23, 2023
d0b6624
safer and better local constants handling
Tal500 Feb 23, 2023
6448aa1
minor fix on rendered local variable
Tal500 Feb 23, 2023
7fe94b8
fix rendered formatting
Tal500 Feb 23, 2023
4e40b75
load externaly systemjs on polyfills testing when needed
Tal500 Feb 23, 2023
3168b7f
simpler raw import of systemjs for testing
Tal500 Feb 23, 2023
8d19a50
insert the "compact" rule to the general linting
Tal500 Feb 23, 2023
a409693
put systemjs dep on dev, and fix the modern polyfill check
Tal500 Feb 24, 2023
a59f971
minor testing package name fix
Tal500 Feb 24, 2023
bf9e41a
Merge branch 'master' into legacy-builds
Tal500 Mar 17, 2023
0dfc032
Merge branch 'master' into legacy-builds
Tal500 Apr 10, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/mighty-carrots-whisper.md
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': minor
---

[feat] add legacy support on JS bundling by auto-integrating with @vitejs/plugin-legacy
16 changes: 15 additions & 1 deletion .eslintrc.json
Expand Up @@ -11,5 +11,19 @@
"ignorePatterns": ["packages/create-svelte/shared/"],
"rules": {
"unicorn/prefer-node-protocol": "error"
}
},
"overrides": [{
"files": ["packages/kit/src/runtime/app/*.js", "packages/kit/src/runtime/client/*.js"],
"env": {
"browser": true
},
"settings": {
"polyfills": ["URL", "URLSearchParams", "Promise", "fetch", "AbortController", "IntersectionObserver"]
},
"plugins": ["compat", "unicorn"],
"rules": {
"compat/compat": "error",
"unicorn/prefer-node-protocol": "error"
}
}]
}
2 changes: 2 additions & 0 deletions package.json
Expand Up @@ -32,7 +32,9 @@
"@rollup/plugin-node-resolve": "^15.0.1",
"@svitejs/changesets-changelog-github-compact": "^1.1.0",
"@typescript-eslint/eslint-plugin": "^5.53.0",
"@typescript-eslint/parser": "^5.0.0",
"eslint": "^8.33.0",
"eslint-plugin-compat": "^4.0.2",
"eslint-plugin-unicorn": "^46.0.0",
"playwright": "^1.29.2",
"prettier": "^2.8.0",
Expand Down
9 changes: 8 additions & 1 deletion packages/kit/package.json
Expand Up @@ -32,6 +32,7 @@
"@types/node": "^16.18.6",
"@types/sade": "^1.7.4",
"@types/set-cookie-parser": "^2.4.2",
"eslint": "^8.32.0",
"marked": "^4.2.3",
"rollup": "^3.7.0",
"svelte": "^3.56.0",
Expand Down Expand Up @@ -90,5 +91,11 @@
"types": "types/index.d.ts",
"engines": {
"node": "^16.14 || >=18"
}
},
"browserslist": [
"> 0.05% and not ie < 11 and not safari < 10 and not chrome < 14",
"ie >= 11",
"chrome >= 14",
"safari >= 10"
]
}
10 changes: 7 additions & 3 deletions packages/kit/src/exports/vite/dev/index.js
Expand Up @@ -119,14 +119,18 @@ export async function dev(vite, vite_config, svelte_config) {
file: `${runtime_base}/client/start.js`,
imports: [],
stylesheets: [],
fonts: []
fonts: [],
legacy_file: null // No legacy support in dev mode
},
app: {
file: `${svelte_config.kit.outDir}/generated/client/app.js`,
imports: [],
stylesheets: [],
fonts: []
}
fonts: [],
legacy_file: null
},
legacy_polyfills_file: null,
modern_polyfills_file: null
},
nodes: manifest_data.nodes.map((node, index) => {
return async () => {
Expand Down
78 changes: 55 additions & 23 deletions packages/kit/src/exports/vite/index.js
Expand Up @@ -174,6 +174,8 @@ function kit({ svelte_config }) {
/** @type {import('vite').ConfigEnv} */
let vite_config_env;

let output_count = 0;

/** @type {boolean} */
let is_build;

Expand Down Expand Up @@ -643,7 +645,7 @@ function kit({ svelte_config }) {
},

/**
* Vite builds a single bundle. We need three bundles: client, server, and service worker.
* Vite builds a single bundle(or two on legacy). We need three bundles: client, server, and service worker.
* The user's package.json scripts will invoke the Vite CLI to execute the server build. We
* then use this hook to kick off builds for the client and service worker.
*/
Expand All @@ -652,6 +654,13 @@ function kit({ svelte_config }) {
async handler(_options) {
if (secondary_build_started) return; // only run this once

++output_count;
const config_output = vite_config.build.rollupOptions.output;
const config_output_length = Array.isArray(config_output) ? config_output.length : 1;
if (output_count < config_output_length) {
return; // Wait untill all output will be done building, since we need the manifest
}

const verbose = vite_config.logLevel === 'info';
const log = logger({ verbose });

Expand Down Expand Up @@ -700,38 +709,61 @@ function kit({ svelte_config }) {

secondary_build_started = true;

const getLastFlat = (/** @type {unknown} */ arrOrObj) =>
Array.isArray(arrOrObj) ? arrOrObj[arrOrObj.length - 1] : arrOrObj;

const { output } = /** @type {import('rollup').RollupOutput} */ (
await vite.build({
configFile: vite_config.configFile,
// CLI args
mode: vite_config_env.mode,
logLevel: vite_config.logLevel,
clearScreen: vite_config.clearScreen,
build: {
minify: initial_config.build?.minify,
assetsInlineLimit: vite_config.build.assetsInlineLimit,
sourcemap: vite_config.build.sourcemap
},
optimizeDeps: {
force: vite_config.optimizeDeps.force
}
})
getLastFlat(
await vite.build({
configFile: vite_config.configFile,
// CLI args
mode: vite_config_env.mode,
logLevel: vite_config.logLevel,
clearScreen: vite_config.clearScreen,
build: {
minify: initial_config.build?.minify,
assetsInlineLimit: vite_config.build.assetsInlineLimit,
sourcemap: vite_config.build.sourcemap
},
optimizeDeps: {
force: vite_config.optimizeDeps.force
}
})
)
);

/** @type {import('vite').Manifest} */
const client_manifest = JSON.parse(read(`${out}/client/${vite_config.build.manifest}`));

build_data.client = {
start: find_deps(
/**
*
* @param {string} entry
*/
const find_file_if_exist = (entry) =>
entry in client_manifest ? client_manifest[entry].file : null;

/**
*
* @param {string} dir
* @param {string} entry_name
* @returns {import('types').AssetDependenciesWithLegacy}
*/
const find_deps_with_optional_legacy = (dir, entry_name) => ({
...find_deps(
client_manifest,
posixify(path.relative('.', `${runtime_directory}/client/start.js`)),
posixify(path.relative('.', `${dir}/${entry_name}.js`)),
false
),
app: find_deps(
client_manifest,
posixify(path.relative('.', `${kit.outDir}/generated/client-optimized/app.js`)),
false
legacy_file: find_file_if_exist(
posixify(path.relative('.', `${dir}/${entry_name}-legacy.js`))
)
});

build_data.client = {
start: find_deps_with_optional_legacy(`${runtime_directory}/client`, 'start'),
app: find_deps_with_optional_legacy(`${kit.outDir}/generated/client-optimized`, 'app'),
legacy_polyfills_file: find_file_if_exist('vite/legacy-polyfills-legacy'),
modern_polyfills_file: find_file_if_exist('vite/legacy-polyfills')
};

const css = output.filter(
Expand Down
6 changes: 5 additions & 1 deletion packages/kit/src/runtime/app/forms.js
Expand Up @@ -108,7 +108,11 @@ export function enhance(form, submit = () => {}) {
},
cache: 'no-store',
body: data,
signal: controller.signal
signal: controller.signal,
// Althought the default value of `credentials` is 'same-origin', we must specify it explicitly,
// since the default value of the (recomended) `whatwg-fetch` polyfill is different (sadly :-( )),
// and equals to 'omit' instead.
credentials: 'same-origin'
});

result = deserialize(await response.text());
Expand Down
55 changes: 52 additions & 3 deletions packages/kit/src/runtime/client/client.js
Expand Up @@ -115,6 +115,7 @@ export function create_client(app, target) {
let root;

// keeping track of the history index in order to prevent popstate navigation events if needed
// eslint-disable-next-line compat/compat -- if the browser doesn't support `history.state` then this will be just undefined
let current_history_index = history.state?.[INDEX_KEY];

if (!current_history_index) {
Expand Down Expand Up @@ -1457,7 +1458,10 @@ export function create_client(app, target) {
},

_start_router: () => {
history.scrollRestoration = 'manual';
// If the browser supports `history.scrollRestoration`
if (history.scrollRestoration) {
history.scrollRestoration = 'manual';
}

// Adopted from Nuxt.js
// Reset scrollRestoration to auto when leaving page, allowing page reload
Expand Down Expand Up @@ -1822,13 +1826,58 @@ async function load_data(url, invalid) {
}

return new Promise(async (resolve) => {
/**
* Kinda support somehow legacy environments that don't support the Stream API.
* @param {Response} response
*/
const sloppy_legacy_friendly_reader_decoder = (response) => {
if ('body' in response && typeof TextDecoder !== 'undefined') {
return {
reader: /** @type {ReadableStream<Uint8Array>} */ (res.body).getReader(),
decoder: /** @type {{decode: (value: BufferSource | string | undefined) => string}} */ (
new TextDecoder()
)
};
}
// otherwise, we're in a legacy environment that doesn't support `Response.body`, so we shall simulate it

/** @type {string[] | undefined} */
let text_lines = undefined;
let current_line = 0;

return {
reader: {
read: async () => {
if (text_lines === undefined) {
const text = await res.text();

// Split the string on \n or \r characters
text_lines = text.split(/\r?\n|\r|\n/g);
}

if (current_line >= text_lines.length) {
return { done: true, value: undefined };
} else {
return { done: false, value: text_lines[current_line++] };
}
}
},
decoder: {
/**
*
* @param {BufferSource | string | undefined} value
*/
decode: (value) => /** @type {string} */ (value)
}
};
};

/**
* Map of deferred promises that will be resolved by a subsequent chunk of data
* @type {Map<string, import('types').Deferred>}
*/
const deferreds = new Map();
const reader = /** @type {ReadableStream<Uint8Array>} */ (res.body).getReader();
const decoder = new TextDecoder();
const { reader, decoder } = sloppy_legacy_friendly_reader_decoder(res);

/**
* @param {any} data
Expand Down