Merge pull request #2749 from colincasey/custom_elements_without_tags

Allows custom element to be defined without a tag
pull/2782/head
Rich Harris 5 years ago committed by GitHub
commit 0bf991070c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -152,10 +152,14 @@ export default class Component {
this.namespace = namespaces[this.component_options.namespace] || this.component_options.namespace;
if (compile_options.customElement) {
this.tag = this.component_options.tag || compile_options.tag;
if (!this.tag) {
throw new Error(`Cannot compile to a custom element without specifying a tag name via options.tag or <svelte:options>`);
if (this.component_options.tag === undefined && compile_options.tag === undefined) {
const svelteOptions = ast.html.children.find(child => child.name === 'svelte:options');
this.warn(svelteOptions, {
code: 'custom-element-no-tag',
message: `No custom element 'tag' option was specified. To automatically register a custom element, specify a name with a hyphen in it, e.g. <svelte:options tag="my-thing"/>. To hide this warning, use <svelte:options tag={null}/>`
});
}
this.tag = this.component_options.tag || compile_options.tag;
} else {
this.tag = this.name;
}
@ -1267,9 +1271,9 @@ function process_component_options(component: Component, nodes) {
const message = `'tag' must be a string literal`;
const tag = get_value(attribute, code, message);
if (typeof tag !== 'string') component.error(attribute, { code, message });
if (typeof tag !== 'string' && tag !== null) component.error(attribute, { code, message });
if (!/^[a-zA-Z][a-zA-Z0-9]*-[a-zA-Z0-9-]+$/.test(tag)) {
if (tag && !/^[a-zA-Z][a-zA-Z0-9]*-[a-zA-Z0-9-]+$/.test(tag)) {
component.error(attribute, {
code: `invalid-tag-property`,
message: `tag name must be two or more words joined by the '-' character`

@ -462,9 +462,13 @@ export default function dom(
${body.length > 0 && body.join('\n\n')}
}
customElements.define("${component.tag}", ${name});
`);
if (component.tag != null) {
builder.add_block(deindent`
customElements.define("${component.tag}", ${name});
`);
}
} else {
const superclass = options.dev ? 'SvelteComponentDev' : 'SvelteComponent';

@ -5,6 +5,7 @@ import { rollup } from 'rollup';
import * as virtual from 'rollup-plugin-virtual';
import * as puppeteer from 'puppeteer';
import { addLineNumbers, loadConfig, loadSvelte } from "../helpers.js";
import { deepEqual } from 'assert';
const page = `
<body>
@ -59,9 +60,11 @@ describe('custom-elements', function() {
const skip = /\.skip$/.test(dir);
const internal = path.resolve('internal.mjs');
const index = path.resolve('index.mjs');
const warnings = [];
(solo ? it.only : skip ? it.skip : it)(dir, async () => {
const config = loadConfig(`./custom-elements/samples/${dir}/_config.js`);
const expected_warnings = config.warnings || [];
const bundle = await rollup({
input: `test/custom-elements/samples/${dir}/test.js`,
@ -84,6 +87,8 @@ describe('custom-elements', function() {
dev: config.dev
});
compiled.warnings.forEach(w => warnings.push(w));
return compiled.js;
}
}
@ -112,6 +117,16 @@ describe('custom-elements', function() {
} catch (err) {
console.log(addLineNumbers(code));
throw err;
} finally {
if (expected_warnings) {
deepEqual(warnings.map(w => ({
code: w.code,
message: w.message,
pos: w.pos,
start: w.start,
end: w.end
})), expected_warnings);
}
}
});
});

@ -0,0 +1,17 @@
export default {
warnings: [{
code: "custom-element-no-tag",
message: "No custom element 'tag' option was specified. To automatically register a custom element, specify a name with a hyphen in it, e.g. <svelte:options tag=\"my-thing\"/>. To hide this warning, use <svelte:options tag={null}/>",
pos: 0,
start: {
character: 0,
column: 0,
line: 1
},
end: {
character: 18,
column: 18,
line: 1
}
}]
};

@ -0,0 +1,7 @@
<svelte:options />
<script>
export let name;
</script>
<h1>Hello {name}!</h1>

@ -0,0 +1,12 @@
import * as assert from 'assert';
import CustomElement from './main.svelte';
export default function (target) {
customElements.define('no-tag', CustomElement);
target.innerHTML = `<no-tag name="world"></no-tag>`;
const el = target.querySelector('no-tag');
const h1 = el.shadowRoot.querySelector('h1');
assert.equal(h1.textContent, 'Hello world!');
}

@ -0,0 +1,3 @@
export default {
warnings: []
};

@ -0,0 +1,7 @@
<svelte:options tag={null} />
<script>
export let name;
</script>
<h1>Hello {name}!</h1>

@ -0,0 +1,12 @@
import * as assert from 'assert';
import CustomElement from './main.svelte';
export default function (target) {
customElements.define('no-tag', CustomElement);
target.innerHTML = `<no-tag name="world"></no-tag>`;
const el = target.querySelector('no-tag');
const h1 = el.shadowRoot.querySelector('h1');
assert.equal(h1.textContent, 'Hello world!');
}
Loading…
Cancel
Save