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] differential legacy builds #2745

Closed
wants to merge 2 commits into from

Conversation

smertelny
Copy link

Trying to solve #12 using @vitejs/legacy-plugin

I was testing it on examples/hn.svelte.dev and it is already working for IE11 with some configuration for svelte.config.js:

const config = {
    ...
    kit: {
	        legacy: {
			targets: ['ie >= 11'],
			additionalLegacyPolyfills: [
				'custom-event-polyfill',
				'core-js/modules/es.promise.js',
				'whatwg-fetch',
				'regenerator-runtime/runtime'
			]
		}
    ...
    }
}
  • BaseURI handwritten polyfill

There are several challenges I could not solve by myself:

  1. Because of Safari 10.1 bug with executing nomodule code there is a problem with generated code for starting sveltekit app (import { start } from "/_app/start-[hash].js";), as Safari will execute this code anyway for both type="module" and nomodule scripts. Vite is adding some code checking for dynamic import support and for preventing Safari from executing nomodule scripts, but all scripts must be in separate js files (more on this in Safari nomodule gist and @vitejs/legacy-plugin) but start function execution is injected into html template.
  2. While hydration in IE11 there is a bug that makes all elements "shuffle" on IE11 (it is better to see this). Was not trying to figure out this problem yet.
  3. The process of finding the right polyfills is not very fast, but I did not want to "preset" something inside (because someone would like to target another browsers) and did not want to add polyfills.io like I saw in Sapper IE. It could be some setting in svelte.config.js file
  4. I am not very strong in testing, so I will need some guidance if this draft will become something like PR.
  5. Strange thing with pnpm-lock.yaml: after installing @vitejs/plugin-legacy +typescript@4.4.4 was deleted. Was it my bad?

Thank you for reading this wall of text =)

@changeset-bot
Copy link

changeset-bot bot commented Nov 4, 2021

⚠️ No Changeset found

Latest commit: b6c04c1

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@benmccann benmccann changed the title #12: Initial commit for differential legacy builds implementation [feat] differential legacy builds Nov 5, 2021
@dishuostec
Copy link

In my experimental implementation, I use a global init function for both module and nomodule.

Without legacy option:

Output:

<html>
	<head>
		...
		<link rel="modulepreload" href="/_app/start-45fd8323.js">
		<link rel="modulepreload" href="/_app/chunks/vendor-7bab4fb1.js">
		<link rel="stylesheet" href="/_app/assets/start-61d1577b.css">

		<script>
		window._sveltekit_init = (start, imt, nodes)=> {
			start({
				target: document.querySelector("#app"),
				paths: {"base":"","assets":""},
				session: {},
				host: location.host,
				route: true,
				spa: true,
				trailing_slash: "never",
				hydrate: null
			});
		}
		</script>
		<script type="module">
			import { start } from "/_app/start-45fd8323.js";
			window._sveltekit_init(start, m=>import(m), "");
		</script>
	</head>
	...
</html>

With legacy:

defaults and not IE 11

const config = {
  ...
  kit: {
    legacy: {
      targets: ['defaults', 'not IE 11']
    }
    ...
  }
}

Legacy polyfills:

{
  'core-js/modules/es.promise',
  'core-js/modules/es.array.iterator',
  'core-js/modules/web.dom-collections.iterator.js',
  'core-js/modules/es.typed-array.int32-array.js',
  'core-js/modules/es.typed-array.sort.js',
  'core-js/modules/es.string.replace.js',
  'core-js/modules/web.url.js',
  'core-js/modules/web.url-search-params.js'
}

Output:

<html>
	<head>
		...
		<link rel="modulepreload" href="/_app/start-45fd8323.js">
		<link rel="modulepreload" href="/_app/chunks/vendor-7bab4fb1.js">
		<link rel="stylesheet" href="/_app/assets/start-61d1577b.css">

		<script>
		window._sveltekit_init = (start, imt, nodes)=> {
			start({
				target: document.querySelector("#app"),
				paths: {"base":"","assets":""},
				session: {},
				host: location.host,
				route: true,
				spa: true,
				trailing_slash: "never",
				hydrate: null
			});
		}
		</script>
		<script type="module">
			import { start } from "/_app/start-45fd8323.js";
			window._sveltekit_init(start, m=>import(m), "");
		</script>
		<script type="module">!function(){try{new Function("m","return import(m)")}catch(o){console.warn("vite: loading legacy build because dynamic import is unsupported, syntax error above should be ignored");var e=document.getElementById("vite-legacy-polyfill"),n=document.createElement("script");n.src=e.src,n.onload=function(){(function(s,i){i(s.getAttribute('data-src')).then(function(m){window._sveltekit_init(m.start,i,s.getAttribute('data-nodes'))})})(document.getElementById('vite-legacy-entry'),function(m){return System.import(m)});},document.body.appendChild(n)}}();</script>
		<script type="nomodule">!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script>
		<script type="nomodule" id="vite-legacy-polyfill" src="/_app/assets/polyfills-legacy.8548b1d0.js"></script>
		<script type="nomodule" id="vite-legacy-entry" data-src="/_app/legacy/start-81013b97.js" data-nodes="">(function(s,i){i(s.getAttribute('data-src')).then(function(m){window._sveltekit_init(m.start,i,s.getAttribute('data-nodes'))})})(document.getElementById('vite-legacy-entry'),function(m){return System.import(m)});</script>
	</head>
	...
</html>

defaults and IE 11

const config = {
  ...
  kit: {
    legacy: {
      targets: ['defaults', 'IE 11']
    }
    ...
  }
}

Legacy polyfills:

{
  'core-js/modules/es.promise',
  'core-js/modules/es.array.iterator',
  'core-js/modules/es.object.to-string.js',
  'core-js/modules/web.dom-collections.for-each.js',
  'core-js/modules/es.object.keys.js',
  'core-js/modules/es.array.slice.js',
  'core-js/modules/es.array.iterator.js',
  'core-js/modules/es.set.js',
  'core-js/modules/es.string.iterator.js',
  'core-js/modules/web.dom-collections.iterator.js',
  'core-js/modules/es.promise.js',
  'core-js/modules/es.typed-array.int32-array.js',
  'core-js/modules/es.typed-array.copy-within.js',
  'core-js/modules/es.typed-array.every.js',
  'core-js/modules/es.typed-array.fill.js',
  'core-js/modules/es.typed-array.filter.js',
  'core-js/modules/es.typed-array.find.js',
  'core-js/modules/es.typed-array.find-index.js',
  'core-js/modules/es.typed-array.for-each.js',
  'core-js/modules/es.typed-array.includes.js',
  'core-js/modules/es.typed-array.index-of.js',
  'core-js/modules/es.typed-array.iterator.js',
  'core-js/modules/es.typed-array.join.js',
  'core-js/modules/es.typed-array.last-index-of.js',
  'core-js/modules/es.typed-array.map.js',
  'core-js/modules/es.typed-array.reduce.js',
  'core-js/modules/es.typed-array.reduce-right.js',
  'core-js/modules/es.typed-array.reverse.js',
  'core-js/modules/es.typed-array.set.js',
  'core-js/modules/es.typed-array.slice.js',
  'core-js/modules/es.typed-array.some.js',
  'core-js/modules/es.typed-array.sort.js',
  'core-js/modules/es.typed-array.subarray.js',
  'core-js/modules/es.typed-array.to-locale-string.js',
  'core-js/modules/es.typed-array.to-string.js',
  'core-js/modules/es.array.sort.js',
  'core-js/modules/es.array.from.js',
  'core-js/modules/es.array.splice.js',
  'core-js/modules/es.function.name.js',
  'core-js/modules/es.string.starts-with.js',
  'core-js/modules/es.string.trim.js',
  'core-js/modules/es.array.concat.js',
  'core-js/modules/es.regexp.exec.js',
  'core-js/modules/es.string.split.js',
  'core-js/modules/es.array.filter.js',
  'core-js/modules/es.array.join.js',
  'core-js/modules/es.map.js',
  'core-js/modules/es.array.map.js',
  'core-js/modules/es.array.fill.js',
  'core-js/modules/es.string.anchor.js',
  'core-js/modules/es.regexp.to-string.js',
  'core-js/modules/es.string.replace.js',
  'core-js/modules/es.symbol.js',
  'core-js/modules/es.symbol.description.js',
  'core-js/modules/es.symbol.iterator.js',
  'core-js/modules/es.object.get-prototype-of.js',
  'core-js/modules/es.reflect.construct.js',
  'core-js/modules/es.reflect.get.js',
  'core-js/modules/es.object.get-own-property-descriptor.js',
  'core-js/modules/es.object.get-own-property-descriptors.js',
  'core-js/modules/es.object.assign.js',
  'regenerator-runtime/runtime.js',
  'core-js/modules/es.array.includes.js',
  'core-js/modules/es.string.includes.js',
  'core-js/modules/es.string.ends-with.js',
  'core-js/modules/web.url.js',
  'core-js/modules/web.url-search-params.js',
  'core-js/modules/es.string.search.js',
  'core-js/modules/es.array.find.js',
  'core-js/modules/es.object.entries.js',
  'core-js/modules/es.number.constructor.js',
  'core-js/modules/es.string.match.js'
}

Output:

<html>
	<head>
		...
		<link rel="modulepreload" href="/_app/start-45fd8323.js">
		<link rel="modulepreload" href="/_app/chunks/vendor-7bab4fb1.js">
		<link rel="stylesheet" href="/_app/assets/start-61d1577b.css">

		<script>
		window._sveltekit_init = (start, imt, nodes)=> {
			start({
				target: document.querySelector("#app"),
				paths: {"base":"","assets":""},
				session: {},
				host: location.host,
				route: true,
				spa: true,
				trailing_slash: "never",
				hydrate: null
			});
		}
		</script>
		<script type="module">
			import { start } from "/_app/start-45fd8323.js";
			window._sveltekit_init(start, m=>import(m), "");
		</script>
		<script type="module">!function(){try{new Function("m","return import(m)")}catch(o){console.warn("vite: loading legacy build because dynamic import is unsupported, syntax error above should be ignored");var e=document.getElementById("vite-legacy-polyfill"),n=document.createElement("script");n.src=e.src,n.onload=function(){(function(s,i){i(s.getAttribute('data-src')).then(function(m){window._sveltekit_init(m.start,i,s.getAttribute('data-nodes'))})})(document.getElementById('vite-legacy-entry'),function(m){return System.import(m)});},document.body.appendChild(n)}}();</script>
		<script type="nomodule">!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script>
		<script type="nomodule" id="vite-legacy-polyfill" src="/_app/assets/polyfills-legacy.7b89e3e3.js"></script>
		<script type="nomodule" id="vite-legacy-entry" data-src="/_app/legacy/start-81013b97.js" data-nodes="">(function(s,i){i(s.getAttribute('data-src')).then(function(m){window._sveltekit_init(m.start,i,s.getAttribute('data-nodes'))})})(document.getElementById('vite-legacy-entry'),function(m){return System.import(m)});</script>
	</head>
	...
</html>

@dominikg dominikg mentioned this pull request Dec 1, 2021
3 tasks
@vercel
Copy link

vercel bot commented Dec 3, 2021

@smertelny is attempting to deploy a commit to the Svelte Team on Vercel.

A member of the Team first needs to authorize it.

@@ -10,6 +10,7 @@
"type": "module",
"dependencies": {
"@sveltejs/vite-plugin-svelte": "^1.0.0-next.30",
"@vitejs/plugin-legacy": "^1.6.2",
Copy link
Contributor

@bfanger bfanger Jan 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could @vitejs/plugin-legacy become an optional dependency?
That would keep the installation fast for non legacy projects

@Tal500
Copy link
Contributor

Tal500 commented Jul 25, 2022

2. While hydration in IE11 there is a bug that makes all elements "shuffle" on IE11 (it is better to see this). Was not trying to figure out this problem yet.=

See my bug report sveltejs/svelte#7723 and the PR which fixes it sveltejs/svelte#7724.
At least one thing can be easily fixed :-)

@@ -67,7 +67,7 @@ export class Renderer {
* @param {{
* Root: CSRComponent;
* fallback: [CSRComponent, CSRComponent];
* target: Node;
* target: Element;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why needed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants