From be3d82733f1e613ccf90d00eb774ef2fc0cd6c12 Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Mon, 31 Jan 2022 23:23:44 +0100 Subject: [PATCH 1/9] [fix] prevent maximum call stack size exceeded error on large pages (#7203) Co-authored-by: milahu Co-authored-by: Simon Co-authored-by: Ben McCann <322311+benmccann@users.noreply.github.com> --- CHANGELOG.md | 4 ++++ package-lock.json | 15 +++++++-------- package.json | 2 +- src/compiler/compile/css/Stylesheet.ts | 3 ++- src/compiler/compile/nodes/shared/map_children.ts | 3 ++- src/compiler/compile/render_dom/index.ts | 7 ++++--- .../compile/render_dom/wrappers/Element/index.ts | 3 ++- .../compile/render_dom/wrappers/IfBlock.ts | 3 ++- src/compiler/utils/mapped_code.ts | 13 +++---------- src/compiler/utils/push_array.ts | 12 ++++++++++++ 10 files changed, 39 insertions(+), 26 deletions(-) create mode 100644 src/compiler/utils/push_array.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bdb6f3964..19c88464f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Svelte changelog +## Unreleased + +* Avoid `maximum call stack size exceeded` errors on large components ([#4694](https://github.com/sveltejs/svelte/issues/4694)) + ## 3.46.3 * Ignore whitespace in `{#each}` blocks when containing elements with `animate:` ([#5477](https://github.com/sveltejs/svelte/pull/5477)) diff --git a/package-lock.json b/package-lock.json index 40ee10e6aa..7681615287 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,7 +5,6 @@ "requires": true, "packages": { "": { - "name": "svelte", "version": "3.46.3", "license": "MIT", "devDependencies": { @@ -24,7 +23,7 @@ "@typescript-eslint/parser": "^4.31.2", "acorn": "^8.4.1", "agadoo": "^1.1.0", - "code-red": "^0.2.4", + "code-red": "^0.2.5", "css-tree": "^1.1.2", "eslint": "^7.32.0", "eslint-plugin-import": "^2.24.2", @@ -1018,9 +1017,9 @@ } }, "node_modules/code-red": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.2.4.tgz", - "integrity": "sha512-tAJQiZviSyB2KUhz+rocKFzCHPkVooX2aFrdpfWDRvxWJaBQTYFJ/Z2TcWqbjXj5oJJBlqd2GxBXdtAhOXySVQ==", + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.2.5.tgz", + "integrity": "sha512-x+uQyJLNS1v0+74eXqM7FMPoM1fU/fN3tdexGWtCuVjCfxADt1TuuEGIGlFyCC2vhgINDctDb/rgSn8/ZDfJsQ==", "dev": true, "dependencies": { "@types/estree": "^0.0.50", @@ -5954,9 +5953,9 @@ } }, "code-red": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.2.4.tgz", - "integrity": "sha512-tAJQiZviSyB2KUhz+rocKFzCHPkVooX2aFrdpfWDRvxWJaBQTYFJ/Z2TcWqbjXj5oJJBlqd2GxBXdtAhOXySVQ==", + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.2.5.tgz", + "integrity": "sha512-x+uQyJLNS1v0+74eXqM7FMPoM1fU/fN3tdexGWtCuVjCfxADt1TuuEGIGlFyCC2vhgINDctDb/rgSn8/ZDfJsQ==", "dev": true, "requires": { "@types/estree": "^0.0.50", diff --git a/package.json b/package.json index a21e7a080e..e20d33f81d 100644 --- a/package.json +++ b/package.json @@ -127,7 +127,7 @@ "@typescript-eslint/parser": "^4.31.2", "acorn": "^8.4.1", "agadoo": "^1.1.0", - "code-red": "^0.2.4", + "code-red": "^0.2.5", "css-tree": "^1.1.2", "eslint": "^7.32.0", "eslint-plugin-import": "^2.24.2", diff --git a/src/compiler/compile/css/Stylesheet.ts b/src/compiler/compile/css/Stylesheet.ts index 39b7be9db6..8f88f0cbd4 100644 --- a/src/compiler/compile/css/Stylesheet.ts +++ b/src/compiler/compile/css/Stylesheet.ts @@ -8,6 +8,7 @@ import { CssNode } from './interfaces'; import hash from '../utils/hash'; import compiler_warnings from '../compiler_warnings'; import { extract_ignores_above_position } from '../../utils/extract_svelte_ignore'; +import { push_array } from '../../utils/push_array'; function remove_css_prefix(name: string): string { return name.replace(/^-((webkit)|(moz)|(o)|(ms))-/, ''); @@ -351,7 +352,7 @@ export default class Stylesheet { const at_rule_declarations = node.block.children .filter(node => node.type === 'Declaration') .map(node => new Declaration(node)); - atrule.declarations.push(...at_rule_declarations); + push_array(atrule.declarations, at_rule_declarations); } current_atrule = atrule; diff --git a/src/compiler/compile/nodes/shared/map_children.ts b/src/compiler/compile/nodes/shared/map_children.ts index 8fe53088bd..e6ad1d7f6e 100644 --- a/src/compiler/compile/nodes/shared/map_children.ts +++ b/src/compiler/compile/nodes/shared/map_children.ts @@ -18,6 +18,7 @@ import Text from '../Text'; import Title from '../Title'; import Window from '../Window'; import { TemplateNode } from '../../../interfaces'; +import { push_array } from '../../../utils/push_array'; export type Children = ReturnType; @@ -60,7 +61,7 @@ export default function map_children(component, parent, scope, children: Templat if (use_ignores) component.pop_ignores(), ignores = []; if (node.type === 'Comment' && node.ignores.length) { - ignores.push(...node.ignores); + push_array(ignores, node.ignores); } if (last) last.next = node; diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index 89af0c297c..9d9699bdbf 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -11,6 +11,7 @@ import { apply_preprocessor_sourcemap } from '../../utils/mapped_code'; import { RawSourceMap, DecodedSourceMap } from '@ampproject/remapping/dist/types/types'; import { flatten } from '../../utils/flatten'; import check_enable_sourcemap from '../utils/check_enable_sourcemap'; +import { push_array } from '../../utils/push_array'; export default function dom( component: Component, @@ -67,7 +68,7 @@ export default function dom( // TODO the deconflicted names of blocks are reversed... should set them here const blocks = renderer.blocks.slice().reverse(); - body.push(...blocks.map(block => { + push_array(body, blocks.map(block => { // TODO this is a horrible mess — renderer.blocks // contains a mixture of Blocks and Nodes if ((block as Block).render) return (block as Block).render(); @@ -562,7 +563,7 @@ export default function dom( }); } - declaration.body.body.push(...accessors); + push_array(declaration.body.body, accessors); body.push(declaration); @@ -599,7 +600,7 @@ export default function dom( } `[0] as ClassDeclaration; - declaration.body.body.push(...accessors); + push_array(declaration.body.body, accessors); body.push(declaration); } diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index 80b4c7ca7a..eb57233ed0 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -26,6 +26,7 @@ import Action from '../../../nodes/Action'; import MustacheTagWrapper from '../MustacheTag'; import RawMustacheTagWrapper from '../RawMustacheTag'; import is_dynamic from '../shared/is_dynamic'; +import { push_array } from '../../../../utils/push_array'; interface BindingGroup { events: string[]; @@ -597,7 +598,7 @@ export default class ElementWrapper extends Wrapper { this.attributes.forEach((attribute) => { if (attribute.node.name === 'class') { const dependencies = attribute.node.get_dependencies(); - this.class_dependencies.push(...dependencies); + push_array(this.class_dependencies, dependencies); } }); diff --git a/src/compiler/compile/render_dom/wrappers/IfBlock.ts b/src/compiler/compile/render_dom/wrappers/IfBlock.ts index 01d49ac9dd..e94404290f 100644 --- a/src/compiler/compile/render_dom/wrappers/IfBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/IfBlock.ts @@ -10,6 +10,7 @@ import { b, x } from 'code-red'; import { walk } from 'estree-walker'; import { is_head } from './shared/is_head'; import { Identifier, Node } from 'estree'; +import { push_array } from '../../../utils/push_array'; function is_else_if(node: ElseBlock) { return ( @@ -166,7 +167,7 @@ export default class IfBlockWrapper extends Wrapper { block.has_outro_method = has_outros; }); - renderer.blocks.push(...blocks); + push_array(renderer.blocks, blocks); } render( diff --git a/src/compiler/utils/mapped_code.ts b/src/compiler/utils/mapped_code.ts index 58f44d7b8c..04fa05be9a 100644 --- a/src/compiler/utils/mapped_code.ts +++ b/src/compiler/utils/mapped_code.ts @@ -2,6 +2,7 @@ import { DecodedSourceMap, RawSourceMap, SourceMapLoader } from '@ampproject/rem import remapping from '@ampproject/remapping'; import { SourceMap } from 'magic-string'; import { Source, Processed } from '../preprocess/types'; +import { push_array } from './push_array'; export type SourceLocation = { line: number; @@ -60,14 +61,6 @@ function merge_tables(this_table: T[], other_table: T[]): [T[], number[], boo return [new_table, idx_map, val_changed, idx_changed]; } -function pushArray(_this: T[], other: T[]) { - // We use push to mutate in place for memory and perf reasons - // We use the for loop instead of _this.push(...other) to avoid the JS engine's function argument limit (65,535 in JavascriptCore) - for (let i = 0; i < other.length; i++) { - _this.push(other[i]); - } -} - export class MappedCode { string: string; map: DecodedSourceMap; @@ -159,10 +152,10 @@ export class MappedCode { } // combine last line + first line - pushArray(m1.mappings[m1.mappings.length - 1], m2.mappings.shift()); + push_array(m1.mappings[m1.mappings.length - 1], m2.mappings.shift()); // append other lines - pushArray(m1.mappings, m2.mappings); + push_array(m1.mappings, m2.mappings); return this; } diff --git a/src/compiler/utils/push_array.ts b/src/compiler/utils/push_array.ts new file mode 100644 index 0000000000..d2c0913c92 --- /dev/null +++ b/src/compiler/utils/push_array.ts @@ -0,0 +1,12 @@ +/** + * Pushes all `items` into `array` using `push`, therefore mutating the array. + * We do this for memory and perf reasons, and because `array.push(...items)` would + * run into a "max call stack size exceeded" error with too many items (~65k). + * @param array + * @param items + */ +export function push_array(array: T[], items: T[]): void { + for (let i = 0; i < items.length; i++) { + array.push(items[i]); + } +} From fc2470494d8c18c7d0d8046540ccb430325c20ad Mon Sep 17 00:00:00 2001 From: Geoff Rich <4992896+geoffrich@users.noreply.github.com> Date: Tue, 1 Feb 2022 13:43:28 -0800 Subject: [PATCH 2/9] [docs] fix broken links (#7194) --- site/content/docs/01-component-format.md | 2 +- site/content/docs/02-template-syntax.md | 2 +- site/content/docs/03-run-time.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/site/content/docs/01-component-format.md b/site/content/docs/01-component-format.md index d1751320c0..1c64094002 100644 --- a/site/content/docs/01-component-format.md +++ b/site/content/docs/01-component-format.md @@ -57,7 +57,7 @@ In development mode (see the [compiler options](/docs#compile-time-svelte-compil If you export a `const`, `class` or `function`, it is readonly from outside the component. Function *expressions* are valid props, however. -Readonly props can be accessed as properties on the element, tied to the component using [`bind:this` syntax](/docs#template-syntax-element-directives-bind-element). +Readonly props can be accessed as properties on the element, tied to the component using [`bind:this` syntax](/docs#template-syntax-component-directives-bind-this). ```sv + + \ No newline at end of file From 7463d5130116e982b36b1459ad568d12a0ad6e70 Mon Sep 17 00:00:00 2001 From: Yosuke Ota Date: Wed, 2 Feb 2022 17:30:25 +0900 Subject: [PATCH 6/9] [fix]: keep space in `
` or when `preserveWhitespace:
 true` (#6990)

Fixes #6437
Fixes #4731
Closes #4737

Whitespace is now untouched inside 
 tag and other tags if preserveWhitespace is true
---
 src/compiler/compile/nodes/Text.ts            | 17 +++++
 .../compile/render_dom/wrappers/Fragment.ts   |  4 +-
 .../compile/render_dom/wrappers/Text.ts       | 10 +--
 .../utils/remove_whitespace_children.ts       |  4 +-
 test/runtime/samples/pre-tag/_config.js       | 57 ++++++++++++++++
 test/runtime/samples/pre-tag/main.svelte      | 34 ++++++++++
 .../samples/preserve-whitespaces/_config.js   | 66 +++++++++++++++++++
 .../samples/preserve-whitespaces/main.svelte  | 34 ++++++++++
 test/server-side-rendering/index.ts           | 10 ++-
 .../samples/pre-tag/_config.js                |  3 +
 .../samples/pre-tag/_expected.html            | 30 +++++++++
 .../samples/pre-tag/main.svelte               | 34 ++++++++++
 .../samples/preserve-whitespaces/_config.js   |  6 ++
 .../preserve-whitespaces/_expected.html       | 34 ++++++++++
 .../samples/preserve-whitespaces/main.svelte  | 34 ++++++++++
 15 files changed, 361 insertions(+), 16 deletions(-)
 create mode 100644 test/runtime/samples/pre-tag/_config.js
 create mode 100644 test/runtime/samples/pre-tag/main.svelte
 create mode 100644 test/runtime/samples/preserve-whitespaces/_config.js
 create mode 100644 test/runtime/samples/preserve-whitespaces/main.svelte
 create mode 100644 test/server-side-rendering/samples/pre-tag/_config.js
 create mode 100644 test/server-side-rendering/samples/pre-tag/_expected.html
 create mode 100644 test/server-side-rendering/samples/pre-tag/main.svelte
 create mode 100644 test/server-side-rendering/samples/preserve-whitespaces/_config.js
 create mode 100644 test/server-side-rendering/samples/preserve-whitespaces/_expected.html
 create mode 100644 test/server-side-rendering/samples/preserve-whitespaces/main.svelte

diff --git a/src/compiler/compile/nodes/Text.ts b/src/compiler/compile/nodes/Text.ts
index 6ea6405dda..347beb9c23 100644
--- a/src/compiler/compile/nodes/Text.ts
+++ b/src/compiler/compile/nodes/Text.ts
@@ -43,4 +43,21 @@ export default class Text extends Node {
 
 		return parent_element.namespace || elements_without_text.has(parent_element.name);
 	}
+
+	keep_space(): boolean {
+		if (this.component.component_options.preserveWhitespace) return true;
+		return this.within_pre();
+	}
+
+	within_pre(): boolean {
+		let node = this.parent;
+		while (node) {
+			if (node.type === 'Element' && node.name === 'pre') {
+				return true;
+			}
+			node = node.parent;
+		}
+
+		return false;
+	}
 }
diff --git a/src/compiler/compile/render_dom/wrappers/Fragment.ts b/src/compiler/compile/render_dom/wrappers/Fragment.ts
index 98805b9639..87ce775ca9 100644
--- a/src/compiler/compile/render_dom/wrappers/Fragment.ts
+++ b/src/compiler/compile/render_dom/wrappers/Fragment.ts
@@ -95,7 +95,7 @@ export default class FragmentWrapper {
 						next_sibling ? (next_sibling.node.type === 'Text' && /^\s/.test(next_sibling.node.data) && trimmable_at(child, next_sibling)) : !child.has_ancestor('EachBlock')
 					);
 
-					if (should_trim) {
+					if (should_trim && !child.keep_space()) {
 						data = trim_end(data);
 						if (!data) continue;
 					}
@@ -127,7 +127,7 @@ export default class FragmentWrapper {
 		if (strip_whitespace) {
 			const first = this.nodes[0] as Text;
 
-			if (first && first.node.type === 'Text') {
+			if (first && first.node.type === 'Text' && !first.node.keep_space()) {
 				first.data = trim_start(first.data);
 				if (!first.data) {
 					first.var = null;
diff --git a/src/compiler/compile/render_dom/wrappers/Text.ts b/src/compiler/compile/render_dom/wrappers/Text.ts
index edff44d1fd..2a342b5678 100644
--- a/src/compiler/compile/render_dom/wrappers/Text.ts
+++ b/src/compiler/compile/render_dom/wrappers/Text.ts
@@ -29,15 +29,7 @@ export default class TextWrapper extends Wrapper {
 		if (this.renderer.component.component_options.preserveWhitespace) return false;
 		if (/[\S\u00A0]/.test(this.data)) return false;
 
-		let node = this.parent && this.parent.node;
-		while (node) {
-			if (node.type === 'Element' && node.name === 'pre') {
-				return false;
-			}
-			node = node.parent;
-		}
-
-		return true;
+		return !this.node.within_pre();
 	}
 
 	render(block: Block, parent_node: Identifier, parent_nodes: Identifier) {
diff --git a/src/compiler/compile/render_ssr/handlers/utils/remove_whitespace_children.ts b/src/compiler/compile/render_ssr/handlers/utils/remove_whitespace_children.ts
index b6c1bf493a..7733c89cb8 100644
--- a/src/compiler/compile/render_ssr/handlers/utils/remove_whitespace_children.ts
+++ b/src/compiler/compile/render_ssr/handlers/utils/remove_whitespace_children.ts
@@ -26,7 +26,7 @@ export default function remove_whitespace_children(children: INode[], next?: INo
 					  trimmable_at(child, next)
 					: !child.has_ancestor('EachBlock');
 
-				if (should_trim) {
+				if (should_trim && !child.keep_space()) {
 					data = trim_end(data);
 					if (!data) continue;
 				}
@@ -47,7 +47,7 @@ export default function remove_whitespace_children(children: INode[], next?: INo
 	}
 
 	const first = nodes[0];
-	if (first && first.type === 'Text') {
+	if (first && first.type === 'Text' && !first.keep_space()) {
 		first.data = trim_start(first.data);
 		if (!first.data) {
 			first.var = null;
diff --git a/test/runtime/samples/pre-tag/_config.js b/test/runtime/samples/pre-tag/_config.js
new file mode 100644
index 0000000000..a2e8feb118
--- /dev/null
+++ b/test/runtime/samples/pre-tag/_config.js
@@ -0,0 +1,57 @@
+export default {
+	test({ assert, target }) {
+		// Test for 
 tag
+		const elementPre = target.querySelector('#pre');
+		// Test for non 
 tag
+		const elementDiv = target.querySelector('#div');
+		// Test for 
 tag in non 
 tag
+		const elementDivWithPre = target.querySelector('#div-with-pre');
+
+		// There is a slight difference in innerHTML because there is a difference in HTML optimization (in jsdom)
+		// depending on how the innerHTML is set.
+		// (There is no difference in the display.)
+		// Reassign innerHTML to add the same optimizations to innerHTML.
+
+		// eslint-disable-next-line no-self-assign
+		elementPre.innerHTML = elementPre.innerHTML;
+		// eslint-disable-next-line no-self-assign
+		elementDiv.innerHTML = elementDiv.innerHTML;
+		// eslint-disable-next-line no-self-assign
+		elementDivWithPre.innerHTML = elementDivWithPre.innerHTML;
+
+		assert.equal(
+			elementPre.innerHTML,
+			`
+  A
+  B
+  
+    C
+    D
+  
+  E
+  F
+`
+		);
+		assert.equal(
+			elementDiv.innerHTML,
+			`A
+  B
+  C
+    D
+  E
+  F`
+		);
+		assert.equal(
+			elementDivWithPre.innerHTML,
+			`
    A
+    B
+    
+      C
+      D
+    
+    E
+    F
+  
` + ); + } +}; diff --git a/test/runtime/samples/pre-tag/main.svelte b/test/runtime/samples/pre-tag/main.svelte new file mode 100644 index 0000000000..ef603b9883 --- /dev/null +++ b/test/runtime/samples/pre-tag/main.svelte @@ -0,0 +1,34 @@ +
+  A
+  B
+  
+    C
+    D
+  
+  E
+  F
+
+ +
+ A + B + + C + D + + E + F +
+ +
+
+    A
+    B
+    
+      C
+      D
+    
+    E
+    F
+  
+
diff --git a/test/runtime/samples/preserve-whitespaces/_config.js b/test/runtime/samples/preserve-whitespaces/_config.js new file mode 100644 index 0000000000..e0c621a18b --- /dev/null +++ b/test/runtime/samples/preserve-whitespaces/_config.js @@ -0,0 +1,66 @@ +export default { + compileOptions: { + preserveWhitespace: true + }, + test({ assert, target }) { + // Test for
 tag
+		const elementPre = target.querySelector('#pre');
+		// Test for non 
 tag
+		const elementDiv = target.querySelector('#div');
+		// Test for 
 tag in non 
 tag
+		const elementDivWithPre = target.querySelector('#div-with-pre');
+
+		// There is a slight difference in innerHTML because there is a difference in HTML optimization (in jsdom)
+		// depending on how the innerHTML is set.
+		// (There is no difference in the display.)
+		// Reassign innerHTML to add the same optimizations to innerHTML.
+
+		// eslint-disable-next-line no-self-assign
+		elementPre.innerHTML = elementPre.innerHTML;
+		// eslint-disable-next-line no-self-assign
+		elementDiv.innerHTML = elementDiv.innerHTML;
+		// eslint-disable-next-line no-self-assign
+		elementDivWithPre.innerHTML = elementDivWithPre.innerHTML;
+
+		assert.equal(
+			elementPre.innerHTML,
+			`
+  A
+  B
+  
+    C
+    D
+  
+  E
+  F
+`
+		);
+		assert.equal(
+			elementDiv.innerHTML,
+			`
+  A
+  B
+  
+    C
+    D
+  
+  E
+  F
+`
+		);
+		assert.equal(
+			elementDivWithPre.innerHTML,
+			`
+  
    A
+    B
+    
+      C
+      D
+    
+    E
+    F
+  
+` + ); + } +}; diff --git a/test/runtime/samples/preserve-whitespaces/main.svelte b/test/runtime/samples/preserve-whitespaces/main.svelte new file mode 100644 index 0000000000..ef603b9883 --- /dev/null +++ b/test/runtime/samples/preserve-whitespaces/main.svelte @@ -0,0 +1,34 @@ +
+  A
+  B
+  
+    C
+    D
+  
+  E
+  F
+
+ +
+ A + B + + C + D + + E + F +
+ +
+
+    A
+    B
+    
+      C
+      D
+    
+    E
+    F
+  
+
diff --git a/test/server-side-rendering/index.ts b/test/server-side-rendering/index.ts index 98d19a6006..f5773e37b6 100644 --- a/test/server-side-rendering/index.ts +++ b/test/server-side-rendering/index.ts @@ -83,9 +83,13 @@ describe('ssr', () => { if (css.code) fs.writeFileSync(`${dir}/_actual.css`, css.code); try { - (compileOptions.preserveComments - ? assert.htmlEqualWithComments - : assert.htmlEqual)(html, expectedHtml); + if (config.withoutNormalizeHtml) { + assert.strictEqual(html.trim(), expectedHtml.trim().replace(/\r\n/g, '\n')); + } else { + (compileOptions.preserveComments + ? assert.htmlEqualWithComments + : assert.htmlEqual)(html, expectedHtml); + } } catch (error) { if (shouldUpdateExpected()) { fs.writeFileSync(`${dir}/_expected.html`, html); diff --git a/test/server-side-rendering/samples/pre-tag/_config.js b/test/server-side-rendering/samples/pre-tag/_config.js new file mode 100644 index 0000000000..39b31839f5 --- /dev/null +++ b/test/server-side-rendering/samples/pre-tag/_config.js @@ -0,0 +1,3 @@ +export default { + withoutNormalizeHtml: true +}; diff --git a/test/server-side-rendering/samples/pre-tag/_expected.html b/test/server-side-rendering/samples/pre-tag/_expected.html new file mode 100644 index 0000000000..7f88acdff4 --- /dev/null +++ b/test/server-side-rendering/samples/pre-tag/_expected.html @@ -0,0 +1,30 @@ +
+  A
+  B
+  
+    C
+    D
+  
+  E
+  F
+
+ +
A + B + C + D + + E + F +
+ +
+    A
+    B
+    
+      C
+      D
+    
+    E
+    F
+  
diff --git a/test/server-side-rendering/samples/pre-tag/main.svelte b/test/server-side-rendering/samples/pre-tag/main.svelte new file mode 100644 index 0000000000..fb240817f7 --- /dev/null +++ b/test/server-side-rendering/samples/pre-tag/main.svelte @@ -0,0 +1,34 @@ +
+  A
+  B
+  
+    C
+    D
+  
+  E
+  F
+
+ +
+ A + B + + C + D + + E + F +
+ +
+
+    A
+    B
+    
+      C
+      D
+    
+    E
+    F
+  
+
diff --git a/test/server-side-rendering/samples/preserve-whitespaces/_config.js b/test/server-side-rendering/samples/preserve-whitespaces/_config.js new file mode 100644 index 0000000000..41eb78446c --- /dev/null +++ b/test/server-side-rendering/samples/preserve-whitespaces/_config.js @@ -0,0 +1,6 @@ +export default { + withoutNormalizeHtml: true, + compileOptions: { + preserveWhitespace: true + } +}; diff --git a/test/server-side-rendering/samples/preserve-whitespaces/_expected.html b/test/server-side-rendering/samples/preserve-whitespaces/_expected.html new file mode 100644 index 0000000000..fb240817f7 --- /dev/null +++ b/test/server-side-rendering/samples/preserve-whitespaces/_expected.html @@ -0,0 +1,34 @@ +
+  A
+  B
+  
+    C
+    D
+  
+  E
+  F
+
+ +
+ A + B + + C + D + + E + F +
+ +
+
+    A
+    B
+    
+      C
+      D
+    
+    E
+    F
+  
+
diff --git a/test/server-side-rendering/samples/preserve-whitespaces/main.svelte b/test/server-side-rendering/samples/preserve-whitespaces/main.svelte new file mode 100644 index 0000000000..fb240817f7 --- /dev/null +++ b/test/server-side-rendering/samples/preserve-whitespaces/main.svelte @@ -0,0 +1,34 @@ +
+  A
+  B
+  
+    C
+    D
+  
+  E
+  F
+
+ +
+ A + B + + C + D + + E + F +
+ +
+
+    A
+    B
+    
+      C
+      D
+    
+    E
+    F
+  
+
From 198883f21fd284ee278daf2209134875d5672657 Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Wed, 2 Feb 2022 09:38:09 +0100 Subject: [PATCH 7/9] update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19c88464f3..f079922149 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ ## Unreleased * Avoid `maximum call stack size exceeded` errors on large components ([#4694](https://github.com/sveltejs/svelte/issues/4694)) +* Keep space in `
` tags or when `preserveWhitespace` is `true`([#6437](https://github.com/sveltejs/svelte/issues/6437), [#4731](https://github.com/sveltejs/svelte/issues/4731))
+* Better error message when trying to use style directives on inline components ([#7177](https://github.com/sveltejs/svelte/issues/7177))
+* Add `FormData` as a known global ([#7199](https://github.com/sveltejs/svelte/pull/7199))
+* Mark `css`/`instance`/`module` Ast properties as optional ([#7204](https://github.com/sveltejs/svelte/pull/7204))
 
 ## 3.46.3
 

From ec903ca7bc45d76045a4ced78cce87783634be8a Mon Sep 17 00:00:00 2001
From: Daniel Sandoval 
Date: Wed, 2 Feb 2022 01:55:30 -0700
Subject: [PATCH 8/9] [docs] "What's new in Svelte" February newsletter (#7202)

---
 ...02-01-whats-new-in-svelte-february-2022.md | 106 ++++++++++++++++++
 1 file changed, 106 insertions(+)
 create mode 100644 site/content/blog/2022-02-01-whats-new-in-svelte-february-2022.md

diff --git a/site/content/blog/2022-02-01-whats-new-in-svelte-february-2022.md b/site/content/blog/2022-02-01-whats-new-in-svelte-february-2022.md
new file mode 100644
index 0000000000..289716e6dd
--- /dev/null
+++ b/site/content/blog/2022-02-01-whats-new-in-svelte-february-2022.md
@@ -0,0 +1,106 @@
+---
+title: "What's new in Svelte: February 2022"
+description: "Rapid-fire releases across Svelte, SvelteKit and the community"
+author: Daniel Sandoval
+authorURL: https://desandoval.net
+---
+
+Happy February, everyone! Over the last month or so, we've seen Svelte and SvelteKit [develop at rapid speed](accelerating-sveltes-development), new community rules across the [Reddit](https://www.reddit.com/r/sveltejs/comments/s9n8ou/new_rules/), [GitHub](https://github.com/sveltejs/community/blob/main/CODE_OF_CONDUCT.md) and [Discord](https://discord.com/channels/457912077277855764/831611707667382303/935264550436102315), and quite a few amazing apps, tutorials and libraries.
+
+Let's take a look...
+
+## Highlights from the Svelte changelog
+- **3.45.0** brought a [new a11y warning `a11y-no-redundant-roles`](https://svelte.dev/docs#accessibility-warnings-a11y-no-redundant-roles), destructuring and caching fixes
+- **3.46.0** added the much requested [`{@const}` tag](https://svelte.dev/docs#template-syntax-const) and [`style:` directive](https://svelte.dev/docs#template-syntax-element-directives-style-property)
+- Check out **3.46.1 - 3.46.3** for fixes to the `{@const}` tag and `style:` directive, along with a number of fixes to animations
+- [AST output is now available in the Svelte REPL](https://svelte.dev/repl/hello-world)
+
+## What's new in SvelteKit
+- `inlineStyleThreshold` allows you to specify where inline stylesheets are inserted into the page ([Docs](https://kit.svelte.dev/docs#configuration-inlinestylethreshold), [#2620](https://github.com/sveltejs/kit/pull/2620))
+- `beforeNavigate`/`afterNavigate` lifecycle functions lets you add functionality before or after a page navigation ([Docs](https://kit.svelte.dev/docs#modules-$app-navigation), [#3293](https://github.com/sveltejs/kit/pull/3293))
+- Platform context can now be passed from adapters ([Docs](https://kit.svelte.dev/docs#adapters-supported-environments-platform-specific-context), [#3429](https://github.com/sveltejs/kit/pull/3429))
+- Hooks now have an `ssr` parameter in `resolve` to make it easier to skip SSR, when needed ([Docs](https://kit.svelte.dev/docs#hooks-handle, [#2804](https://github.com/sveltejs/kit/pull/2804))
+- `$page.stuff` provides a mechanism for pages to pass data 'upward' to layouts ([Docs](https://kit.svelte.dev/docs#loading-input-stuff), [#3252](https://github.com/sveltejs/kit/pull/3252))
+- Fallthrough routes let you specify where to route when an route can't be loaded ([Docs](https://kit.svelte.dev/docs#routing-advanced-fallthrough-routes), [#3217](https://github.com/sveltejs/kit/pull/3217))
+
+**New configs**
+- Content Security Policy (CSP) is now supported for increased security when using inline javascript or stylesheets ([Docs](https://kit.svelte.dev/docs#configuration-csp), [#3499](https://github.com/sveltejs/kit/pull/3499))
+- `kit.routes` config allows you to customise public/private modules during build ([Docs](https://kit.svelte.dev/docs#configuration-routes), [#3576](https://github.com/sveltejs/kit/pull/3576))
+- `prerender.createIndexFiles` config lets you prerender index.html files as their subfolder's name ([Docs](https://kit.svelte.dev/docs#configuration-prerender), [#2632](https://github.com/sveltejs/kit/pull/2632))
+- HTTP methods can now be overridden using `kit.methodOverride` ([Docs](https://kit.svelte.dev/docs#routing-endpoints-http-method-overrides), [#2989](https://github.com/sveltejs/kit/pull/2989))
+
+**Config changes**
+- `config.kit.hydrate` and `config.kit.router` are now nested under `config.kit.browser` ([Docs](https://kit.svelte.dev/docs#configuration-browser), [3578](https://github.com/sveltejs/kit/pull/3578))
+
+**Breaking change**
+- use `Request` and `Response` objects in endpoints and hooks ([#3384](https://github.com/sveltejs/kit/pull/3384))
+
+
+---
+
+## Community Showcase
+
+**Apps & Sites**
+- [timb(re)](https://paullj.github.io/timb) is a live music programming environment
+- [Music for Programming](https://musicforprogramming.net/latest/) is a series of mixes intended for listening while `${task}` to focus the brain and inspire the mind
+- [Team Tale](https://teamtale.app/) allows two authors to write the same story in a tag-team sort of fashion
+- [Puzzlez](https://www.puzzlez.io/) is an online place to play Sudoku and Wordle
+- [Closed Caption Creator](https://www.closedcaptioncreator.com/) makes it easy to add subtitles to your video on Windows, Mac and Google Chrome
+- [SC3Lab](https://sc3-lab.netlify.app/) is a code generator for experimenting with svelte-cubed and three.js
+- [Donkeytype](https://github.com/0ql/Donkeytype) is a minimalistic and lightweight typingtest inspired by Monkeytype.
+- [Above](https://above.silas.pro/) is a visual routine timer built for the ADHD/autistic mind
+- [base.report](https://base.report/) is a modern research platform for serious investors
+- [String](https://string.kampsy.xyz/) turns your Phone into a secure portable audio recorder, making it easy to capture and share personal notes, family moments, classroom lectures, and more
+- [The Raytracer Challenge REPL](https://github.com/jakobwesthoff/the_raytracer_challenge_repl) provides a live editor interface to configure a raytraced scene and render it live in any modern browser
+- [awesome-svelte-kit](https://github.com/janosh/awesome-svelte-kit) is a list of awesome examples of SvelteKit in the wild
+- [Map Projection Explorer](https://www.geo-projections.com/) lets you explore different map projections and explains their differences
+- [Rubiks](https://github.com/MeharGaur/rubiks) is a Rubik's Cube simulator
+- [Pianisto](https://pianisto.net/) is a working piano made with SVG, ToneJS and a lot of patience
+
+Want to work on a SvelteKit site with others, [try contributing to the Svelte Society site](https://github.com/svelte-society/sveltesociety-2021/issues)!
+
+
+**Learning and Listening**
+
+_To Read_
+- [Accelerating Svelte's Development](https://svelte.dev/blog/accelerating-sveltes-development) by Ben McCann
+- [Storybook for Vite](https://storybook.js.org/blog/storybook-for-vite/)
+- [Let's learn SvelteKit by building a static Markdown blog from scratch](https://joshcollinsworth.com/blog/build-static-sveltekit-markdown-blog) by Josh Collinsworth
+- [Building an iOS app with Svelte, Capacitor and Firebase](https://harryherskowitz.com/2022/01/05/tapedrop-app.html) by Harry Herskowitz
+- [Mutating Query Params in SvelteKit Without Page Reloads or Navigations](https://dev.to/mohamadharith/mutating-query-params-in-sveltekit-without-page-reloads-or-navigations-2i2b) and [Workaround for Bubbling Custom Events in Svelte](https://dev.to/mohamadharith/workaround-for-bubbling-custom-events-in-svelte-3khk) by Mohamad Harith
+- [How to build a full stack serverless application with Svelte and GraphQL](https://dev.to/shadid12/how-to-build-a-full-stack-serverless-application-with-svelte-graphql-and-fauna-5427) by Shadid Haque
+- [How to Deploy SvelteKit Apps to Github Pages](https://sveltesaas.com/articles/sveltekit-github-pages-guide/)
+- [Creating a dApp with SvelteKit](https://anthonyriley.org/2021/12/31/creating-a-dapp-with-sveltekit/) by Anthony Riley
+- [Comparing Svelte Reactivity Options](https://opendirective.net/2022/01/06/comparing-svelte-reactivity-options/) by Steve Lee
+
+_To Watch_
+- [Integrating Storybook with SvelteKit](https://www.youtube.com/watch?v=Kc1ULlfyUcw) and [Integrating FaunaDB with Svelte](https://www.youtube.com/watch?v=zaoLZc76uZM) by the Svelte Sirens
+- [SvelteKit Crash Course Tutorial](https://www.youtube.com/watch?v=9OlLxkaeVvw&list=PL4cUxeGkcC9hpM9ARM59Ve3jqcb54dqiP) by The Net Ninja
+- [Svelte for Beginners](https://www.youtube.com/watch?v=BrkrOjknC_E&list=PLA9WiRZ-IS_ylnMYxIFCsZN6xVVSvLuHk) by Joy of Code
+- [SvelteKit For Beginners | Movie App Tutorial](https://www.youtube.com/watch?v=ydR_M0fw9Xc) by Dev Ed
+- [SvelteKit $app/stores](https://www.youtube.com/watch?v=gBPhr1xbgaQ) by lihautan
+- [Sveltekit - Get All Routes/Pages](https://www.youtube.com/watch?v=Y_NE2R3HuOU) by WebJeda
+
+_To Listen To_
+- [New Year, New Svelte!?](https://share.transistor.fm/s/36212cdc) from Svelte Radio
+- [So much Sveltey goodness (featuring Rich Harris)](https://changelog.com/jsparty/205) from JS Party
+- [The Other Side of Tech: A Documentarian Perspective (with Stefan Kingham)](https://codingcat.dev/podcast/2-4-the-other-side-of-tech-a-documentarian-perspective) from Purrfect.dev
+
+**Libraries, Tools & Components**
+- [threlte](https://github.com/grischaerbe/threlte) is a three.js component library for Svelte
+- [svelte-formify](https://github.com/nodify-at/svelte-formify) is a library to manage and validate forms that uses decorators to define validations
+- [gQuery](https://github.com/leveluptuts/gQuery) is a GraphQL Fetcher & Cache for Svelte Kit
+- [Unlock-protocol](https://github.com/novum-insights/sveltekit-unlock-firebase) is an integration to help login with MetaMask, Firebase, and paywall customers
+- [AgnosticUI](https://github.com/AgnosticUI/agnosticui) is a set of UI primitives that start their lives in clean HTML and CSS
+- [Vitebook](https://github.com/vitebook/vitebook) is a fast and lightweight alternative to Storybook that's powered by Vite
+- [SwyxKit](https://swyxkit.netlify.app/) is an opinionated blog starter for SvelteKit + Tailwind + Netlify. Refreshed for 2022!
+- [svelte-themes](https://github.com/beynar/svelte-themes) is an abstraction for themes in your SvelteKit app
+- [svelte-transition](https://www.npmjs.com/package/svelte-transition) is a Svelte component to make using CSS class based transitions easier - ideally suited for use with TailwindCSS
+- [Svelte Inview](https://www.npmjs.com/package/svelte-inview) is a Svelte action that monitors an element enters or leaves the viewport/parent element
+- [svelte-inline-compile](https://github.com/DockYard/svelte-inline-compile) is a babel transform that allows for a much more pleasant experience when testing svelte components using Jest and `@testing-library/svelte`
+- [@feltcoop/svelte-mutable-store](https://github.com/feltcoop/svelte-mutable-store) is a Svelte store for mutable values with an `immutable` compiler option
+- [headless-svelte-ui](https://www.npmjs.com/package/@bojalelabs/headless-svelte-ui) is a group of headless components that can be used in building Svelte Apps.
+
+Did we miss something? Need help bringing your next idea to life in Svelte? Join us on [Reddit](https://www.reddit.com/r/sveltejs/) or [Discord](https://discord.com/invite/yy75DKs).
+
+See ya next month!

From 1f9efeac549f2eabb546320eaaa4eadb2171f363 Mon Sep 17 00:00:00 2001
From: Ignatius Bagus 
Date: Wed, 2 Feb 2022 17:33:53 +0700
Subject: [PATCH 9/9] [blog] fix link formatting

---
 .../blog/2022-02-01-whats-new-in-svelte-february-2022.md        | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/site/content/blog/2022-02-01-whats-new-in-svelte-february-2022.md b/site/content/blog/2022-02-01-whats-new-in-svelte-february-2022.md
index 289716e6dd..990295bb89 100644
--- a/site/content/blog/2022-02-01-whats-new-in-svelte-february-2022.md
+++ b/site/content/blog/2022-02-01-whats-new-in-svelte-february-2022.md
@@ -19,7 +19,7 @@ Let's take a look...
 - `inlineStyleThreshold` allows you to specify where inline stylesheets are inserted into the page ([Docs](https://kit.svelte.dev/docs#configuration-inlinestylethreshold), [#2620](https://github.com/sveltejs/kit/pull/2620))
 - `beforeNavigate`/`afterNavigate` lifecycle functions lets you add functionality before or after a page navigation ([Docs](https://kit.svelte.dev/docs#modules-$app-navigation), [#3293](https://github.com/sveltejs/kit/pull/3293))
 - Platform context can now be passed from adapters ([Docs](https://kit.svelte.dev/docs#adapters-supported-environments-platform-specific-context), [#3429](https://github.com/sveltejs/kit/pull/3429))
-- Hooks now have an `ssr` parameter in `resolve` to make it easier to skip SSR, when needed ([Docs](https://kit.svelte.dev/docs#hooks-handle, [#2804](https://github.com/sveltejs/kit/pull/2804))
+- Hooks now have an `ssr` parameter in `resolve` to make it easier to skip SSR, when needed ([Docs](https://kit.svelte.dev/docs#hooks-handle), [#2804](https://github.com/sveltejs/kit/pull/2804))
 - `$page.stuff` provides a mechanism for pages to pass data 'upward' to layouts ([Docs](https://kit.svelte.dev/docs#loading-input-stuff), [#3252](https://github.com/sveltejs/kit/pull/3252))
 - Fallthrough routes let you specify where to route when an route can't be loaded ([Docs](https://kit.svelte.dev/docs#routing-advanced-fallthrough-routes), [#3217](https://github.com/sveltejs/kit/pull/3217))