From 7836f409aac8a3dc0bca42f1ecc3fc0241c90bff Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sat, 17 Aug 2019 00:24:12 -0400 Subject: [PATCH 1/7] support is attribute, with a warning - fixes #3182 --- src/compiler/compile/nodes/Element.ts | 7 +++++++ .../render_dom/wrappers/Element/index.ts | 5 +++++ src/runtime/internal/dom.ts | 4 ++++ .../samples/extended-builtin/_config.js | 17 +++++++++++++++++ .../samples/extended-builtin/fancy-button.js | 2 ++ .../samples/extended-builtin/main.svelte | 7 +++++++ .../samples/extended-builtin/test.js | 15 +++++++++++++++ 7 files changed, 57 insertions(+) create mode 100644 test/custom-elements/samples/extended-builtin/_config.js create mode 100644 test/custom-elements/samples/extended-builtin/fancy-button.js create mode 100644 test/custom-elements/samples/extended-builtin/main.svelte create mode 100644 test/custom-elements/samples/extended-builtin/test.js diff --git a/src/compiler/compile/nodes/Element.ts b/src/compiler/compile/nodes/Element.ts index e08e1f963d..593f303a2f 100644 --- a/src/compiler/compile/nodes/Element.ts +++ b/src/compiler/compile/nodes/Element.ts @@ -415,6 +415,13 @@ export default class Element extends Node { } } + if (name === 'is') { + component.warn(attribute, { + code: 'avoid-is', + message: `The 'is' attribute is not supported cross-browser and should be avoided` + }); + } + attribute_map.set(attribute.name, attribute); }); diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index 7480c31cc7..1d1729c18c 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -383,6 +383,11 @@ export default class ElementWrapper extends Wrapper { return `@_document.createElementNS("${namespace}", "${name}")`; } + const is = this.attributes.find(attr => attr.node.name === 'is'); + if (is) { + return `@element_is("${name}", ${is.render_chunks().join(' + ')});` + } + return `@element("${name}")`; } diff --git a/src/runtime/internal/dom.ts b/src/runtime/internal/dom.ts index 25c804ff34..a918c3193d 100644 --- a/src/runtime/internal/dom.ts +++ b/src/runtime/internal/dom.ts @@ -20,6 +20,10 @@ export function element(name: K) { return document.createElement(name); } +export function element_is(name: K, is: string) { + return document.createElement(name, { is }); +} + export function object_without_properties(obj: T, exclude: K[]) { // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion const target = {} as Pick>; diff --git a/test/custom-elements/samples/extended-builtin/_config.js b/test/custom-elements/samples/extended-builtin/_config.js new file mode 100644 index 0000000000..08580e780a --- /dev/null +++ b/test/custom-elements/samples/extended-builtin/_config.js @@ -0,0 +1,17 @@ +export default { + warnings: [{ + code: "avoid-is", + message: "The 'is' attribute is not supported cross-browser and should be avoided", + pos: 97, + start: { + character: 97, + column: 8, + line: 7 + }, + end: { + character: 114, + column: 25, + line: 7 + } + }] +}; diff --git a/test/custom-elements/samples/extended-builtin/fancy-button.js b/test/custom-elements/samples/extended-builtin/fancy-button.js new file mode 100644 index 0000000000..eaa7d84135 --- /dev/null +++ b/test/custom-elements/samples/extended-builtin/fancy-button.js @@ -0,0 +1,2 @@ +class FancyButton extends HTMLButtonElement {} +customElements.define('fancy-button', FancyButton, { extends: 'button' }); \ No newline at end of file diff --git a/test/custom-elements/samples/extended-builtin/main.svelte b/test/custom-elements/samples/extended-builtin/main.svelte new file mode 100644 index 0000000000..0919d9585e --- /dev/null +++ b/test/custom-elements/samples/extended-builtin/main.svelte @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/test/custom-elements/samples/extended-builtin/test.js b/test/custom-elements/samples/extended-builtin/test.js new file mode 100644 index 0000000000..d676fd137b --- /dev/null +++ b/test/custom-elements/samples/extended-builtin/test.js @@ -0,0 +1,15 @@ +import * as assert from 'assert'; +import CustomElement from './main.svelte'; + +export default function (target) { + new CustomElement({ + target + }); + + assert.equal(target.innerHTML, ''); + + const el = target.querySelector('custom-element'); + const button = el.shadowRoot.querySelector('button'); + + assert.ok(button instanceof customElements.get('fancy-button')); +} \ No newline at end of file From a0b48f98252d786bba56e6c1a100885a18b12015 Mon Sep 17 00:00:00 2001 From: nbgoodall Date: Sun, 18 Aug 2019 19:50:41 +0100 Subject: [PATCH 2/7] Add Zevvle logo to 'Who is using Svelte' section --- site/src/routes/_components/WhosUsingSvelte.svelte | 3 ++- site/static/organisations/zevvle.svg | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 site/static/organisations/zevvle.svg diff --git a/site/src/routes/_components/WhosUsingSvelte.svelte b/site/src/routes/_components/WhosUsingSvelte.svelte index 9169dbd1cd..043dd8e5ef 100644 --- a/site/src/routes/_components/WhosUsingSvelte.svelte +++ b/site/src/routes/_components/WhosUsingSvelte.svelte @@ -53,6 +53,7 @@ Deck logo From-Now-On logo GoDaddy logo + HealthTree logo itslearning logo Mustlab logo Nesta logo @@ -69,6 +70,6 @@ Thunderdome logo Tokopedia logo Webdesq logo - HealthTree logo + Zevvle logo + your company? diff --git a/site/static/organisations/zevvle.svg b/site/static/organisations/zevvle.svg new file mode 100644 index 0000000000..45a26c7a7c --- /dev/null +++ b/site/static/organisations/zevvle.svg @@ -0,0 +1 @@ + \ No newline at end of file From b23839fb5f6943e94213026c6ae5e8e878edf3ac Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 18 Aug 2019 19:55:35 -0400 Subject: [PATCH 3/7] add custom element documentation --- site/content/docs/03-run-time.md | 49 +++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/site/content/docs/03-run-time.md b/site/content/docs/03-run-time.md index 193e880ea6..656ee147a4 100644 --- a/site/content/docs/03-run-time.md +++ b/site/content/docs/03-run-time.md @@ -907,7 +907,54 @@ app.count += 1; ### Custom element API -* TODO +--- + +Svelte components can also be compiled to custom elements (aka web components) using the `customElements: true` compiler option. You should specify a tag name for the component using the [``](docs#svelte_options) element. + +```html + + + + +

Hello {name}!

+ +``` + +--- + +Alternatively, use `tag={null}` to indicate that the consumer of the custom element should name it. + +```js +import MyElement from './MyElement.svelte'; + +customElements.define('my-element', MyElement); +``` + +--- + +By default, custom elements are compiled with `accessors: true`, which means that any [props](docs#Attributes_and_props) are exposed as properties of the DOM element (as well as being readable/writable as attributes, where possible). + +To prevent this, add `accessors={false}` to ``. + +```js +const el = document.querySelector('my-element'); + +// get the current value of the 'name' prop +console.log(el.name); + +// set a new value, updating the shadow DOM +el.name = 'everybody'; +``` + +Custom elements can be a useful way to package components for consumption in a non-Svelte app, as they will work with vanilla HTML and JavaScript as well as [most frameworks](https://custom-elements-everywhere.com/). There are, however, some important differences to be aware of: + +* Styles are *encapsulated*, rather than merely *scoped*. This means that any non-component styles (such as you might have in a `global.css` file) will not apply to the custom element, including styles with the `:global(...)` modifier +* Instead of being extracted out as a separate .css file, styles are inlined into the component as a JavaScript string +* Custom elements are not generally suitable for server-side rendering, as the shadow DOM is invisible until JavaScript loads +* Polyfills are required to support older browsers + ### Server-side component API From de24efd3b86a16433c1ff4c986f061ac0985bd89 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 18 Aug 2019 20:08:17 -0400 Subject: [PATCH 4/7] small fix --- site/content/docs/03-run-time.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/content/docs/03-run-time.md b/site/content/docs/03-run-time.md index 656ee147a4..b06911a4de 100644 --- a/site/content/docs/03-run-time.md +++ b/site/content/docs/03-run-time.md @@ -909,7 +909,7 @@ app.count += 1; --- -Svelte components can also be compiled to custom elements (aka web components) using the `customElements: true` compiler option. You should specify a tag name for the component using the [``](docs#svelte_options) element. +Svelte components can also be compiled to custom elements (aka web components) using the `customElements: true` compiler option. You should specify a tag name for the component using the `` [element](docs#svelte_options). ```html From 08be15e3aea40a15d1231e18e34143b12b9ea346 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 18 Aug 2019 20:15:26 -0400 Subject: [PATCH 5/7] add some more CE docs --- site/content/docs/03-run-time.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/site/content/docs/03-run-time.md b/site/content/docs/03-run-time.md index b06911a4de..d5653dd288 100644 --- a/site/content/docs/03-run-time.md +++ b/site/content/docs/03-run-time.md @@ -934,6 +934,18 @@ customElements.define('my-element', MyElement); --- +Once a custom element has been defined, it can be used as a regular DOM element: + +```js +document.body.innerHTML = ` + +

This is some slotted content

+
+`; +``` + +--- + By default, custom elements are compiled with `accessors: true`, which means that any [props](docs#Attributes_and_props) are exposed as properties of the DOM element (as well as being readable/writable as attributes, where possible). To prevent this, add `accessors={false}` to ``. @@ -953,6 +965,8 @@ Custom elements can be a useful way to package components for consumption in a n * Styles are *encapsulated*, rather than merely *scoped*. This means that any non-component styles (such as you might have in a `global.css` file) will not apply to the custom element, including styles with the `:global(...)` modifier * Instead of being extracted out as a separate .css file, styles are inlined into the component as a JavaScript string * Custom elements are not generally suitable for server-side rendering, as the shadow DOM is invisible until JavaScript loads +* In Svelte, slotted content renders *lazily*. In the DOM, it renders *eagerly*. In other words, it will always be created even if the component's `` element is inside an `{#if ...}` block. Similarly, including a `` in an `{#each ...}` block will not cause the slotted content to be rendered multiple times +* The `let:` directive has no effect * Polyfills are required to support older browsers From b73941c8cf46b8c886f9045fc750041d409b9a90 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Mon, 19 Aug 2019 08:00:47 -0400 Subject: [PATCH 6/7] fix deps, tidy up query --- package-lock.json | 10 ---------- package.json | 4 ---- site/package-lock.json | 15 ++++++++++----- site/package.json | 3 ++- site/src/routes/repl/[id]/index.json.js | 5 +++-- 5 files changed, 15 insertions(+), 22 deletions(-) diff --git a/package-lock.json b/package-lock.json index c7d7a3ea0e..c84f5146a0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -535,11 +535,6 @@ "safe-buffer": "~5.1.1" } }, - "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" - }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -1306,11 +1301,6 @@ "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", "dev": true }, - "flru": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/flru/-/flru-1.0.2.tgz", - "integrity": "sha512-kWyh8ADvHBFz6ua5xYOPnUroZTT/bwWfrCeL0Wj1dzG4/YOmOcfJ99W8dOVyyynJN35rZ9aCOtHChqQovV7yog==" - }, "foreground-child": { "version": "1.5.6", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", diff --git a/package.json b/package.json index a8570f5e47..a36ead856e 100644 --- a/package.json +++ b/package.json @@ -98,9 +98,5 @@ ], "sourceMap": true, "instrument": true - }, - "dependencies": { - "cookie": "^0.4.0", - "flru": "^1.0.2" } } diff --git a/site/package-lock.json b/site/package-lock.json index f80a81e9d9..a36dea4aeb 100644 --- a/site/package-lock.json +++ b/site/package-lock.json @@ -1647,6 +1647,11 @@ "safe-buffer": "~5.1.1" } }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, "core-js": { "version": "2.6.5", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.5.tgz", @@ -1906,6 +1911,11 @@ "is-buffer": "~2.0.3" } }, + "flru": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/flru/-/flru-1.0.2.tgz", + "integrity": "sha512-kWyh8ADvHBFz6ua5xYOPnUroZTT/bwWfrCeL0Wj1dzG4/YOmOcfJ99W8dOVyyynJN35rZ9aCOtHChqQovV7yog==" + }, "for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -3840,11 +3850,6 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" - }, "validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", diff --git a/site/package.json b/site/package.json index 3b98cbb858..c9ecacbf0e 100644 --- a/site/package.json +++ b/site/package.json @@ -15,8 +15,10 @@ "dependencies": { "@polka/redirect": "^1.0.0-next.0", "@polka/send": "^1.0.0-next.3", + "cookie": "^0.4.0", "devalue": "^2.0.0", "do-not-zip": "^1.0.0", + "flru": "^1.0.2", "httpie": "^1.1.2", "jsonwebtoken": "^8.5.1", "marked": "^0.7.0", @@ -24,7 +26,6 @@ "polka": "^1.0.0-next.4", "prismjs": "^1.17.1", "sirv": "^0.4.2", - "uuid": "^3.3.2", "yootils": "0.0.16" }, "devDependencies": { diff --git a/site/src/routes/repl/[id]/index.json.js b/site/src/routes/repl/[id]/index.json.js index d0b2a11d59..8c7dabb14a 100644 --- a/site/src/routes/repl/[id]/index.json.js +++ b/site/src/routes/repl/[id]/index.json.js @@ -23,7 +23,7 @@ async function import_gist(req, res) { if (!user) { const { id, name, login, avatar_url } = data.owner; - [user] = await query(` + user = await find(` insert into users(uid, name, username, avatar) values ($1, $2, $3, $4) returning * @@ -45,7 +45,8 @@ async function import_gist(req, res) { // add gist to database... await query(` insert into gists(uid, user_id, name, files) - values ($1, $2, $3, $4) returning *`, [req.params.id, user.id, data.description, JSON.stringify(files)]); + values ($1, $2, $3, $4) + `, [req.params.id, user.id, data.description, JSON.stringify(files)]); send(res, 200, { uid: req.params.id, From eb9e405916ac6d7231fe7c6387ed04cb07dfd955 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Mon, 19 Aug 2019 08:07:55 -0400 Subject: [PATCH 7/7] remove JWT stuff from .env.example --- site/.env.example | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/site/.env.example b/site/.env.example index c59f6f7272..4de2f6111a 100644 --- a/site/.env.example +++ b/site/.env.example @@ -5,8 +5,4 @@ BASEURL= DATABASE_URL= GITHUB_CLIENT_ID= GITHUB_CLIENT_SECRET= -MAPBOX_ACCESS_TOKEN= - -JWT_EXP=30d -JWT_ALG=HS512 -JWT_KEY= +MAPBOX_ACCESS_TOKEN= \ No newline at end of file