Skip to content

Commit

Permalink
feat: Add support for style injection in compiler (#302)
Browse files Browse the repository at this point in the history
* feat: add style injection

* test: add integration test for style injection

* test: fix compiler snapshot tests
  • Loading branch information
pmdartus authored May 16, 2018
1 parent 634f01e commit 3b754f8
Show file tree
Hide file tree
Showing 26 changed files with 391 additions and 301 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ function tmpl($api, $cmp, $slotset, $ctx) {
}

if (style) {
var tagName = 'x-class_and_template';
var token = 'x-class_and_template_class_and_template';
__setKey(tmpl, "token", token);
__setKey(tmpl, "style", style(tagName, token));
__setKey(tmpl, "token", 'x-class_and_template_class_and_template');

var style$1 = __callKey1(document, "createElement", 'style');
__setKey(style$1, "type", 'text/css');
__setKey(__getKey(style$1, "dataset"), "token", 'x-class_and_template_class_and_template');
__setKey(style$1, "textContent", style('x-class_and_template', 'x-class_and_template_class_and_template'));
__callKey1(__getKey(document, "head"), "appendChild", style$1);
}

var Test = 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ function tmpl($api, $cmp, $slotset, $ctx) {
}

if (style) {
const tagName = 'x-default';
const token = 'x-default_default';
tmpl.token = token;
tmpl.style = style(tagName, token);
tmpl.token = 'x-default_default';

const style$$1 = document.createElement('style');
style$$1.type = 'text/css';
style$$1.dataset.token = 'x-default_default';
style$$1.textContent = style('x-default', 'x-default_default');
document.head.appendChild(style$$1);
}

class Default extends Element {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ function tmpl($api, $cmp, $slotset, $ctx) {
}

if (style) {
const tagName = 'x-class_and_template';
const token = 'x-class_and_template_class_and_template';
tmpl.token = token;
tmpl.style = style(tagName, token);
tmpl.token = 'x-class_and_template_class_and_template';

const style$$1 = document.createElement('style');
style$$1.type = 'text/css';
style$$1.dataset.token = 'x-class_and_template_class_and_template';
style$$1.textContent = style('x-class_and_template', 'x-class_and_template_class_and_template');
document.head.appendChild(style$$1);
}

const Test = 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@ function tmpl($api, $cmp, $slotset, $ctx) {
}

if (style) {
const tagName = 'x-external';
const token = 'x-external_external';
tmpl.token = token;
tmpl.style = style(tagName, token);
tmpl.token = 'x-external_external';

const style$$1 = document.createElement('style');
style$$1.type = 'text/css';
style$$1.dataset.token = 'x-external_external';
style$$1.textContent = style('x-external', 'x-external_external');
document.head.appendChild(style$$1);
}

class Foo extends Element {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@ function tmpl($api, $cmp, $slotset, $ctx) {
}

if (style) {
const tagName = 'x-cmp1';
const token = 'x-cmp1_cmp1';
tmpl.token = token;
tmpl.style = style(tagName, token);
tmpl.token = 'x-cmp1_cmp1';

const style$$1 = document.createElement('style');
style$$1.type = 'text/css';
style$$1.dataset.token = 'x-cmp1_cmp1';
style$$1.textContent = style('x-cmp1', 'x-cmp1_cmp1');
document.head.appendChild(style$$1);
}

class Cmp1 extends Element {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ function tmpl($api, $cmp, $slotset, $ctx) {
return [];
}
if (style) {
const tagName = 'x-node_env';
const token = 'x-node_env_node_env';
tmpl.token = token;
tmpl.style = style(tagName, token);
tmpl.token = 'x-node_env_node_env';
const style$$1 = document.createElement('style');
style$$1.type = 'text/css';
style$$1.dataset.token = 'x-node_env_node_env';
style$$1.textContent = style('x-node_env', 'x-node_env_node_env');
document.head.appendChild(style$$1);
}
class ClassAndTemplate extends Element {
connectedCallback() {
Expand All @@ -21,4 +23,4 @@ class ClassAndTemplate extends Element {
}
}
ClassAndTemplate.style = tmpl.style;
export default ClassAndTemplate;
export default ClassAndTemplate;
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ function tmpl($api, $cmp, $slotset, $ctx) {
return [];
}
if (style) {
const tagName = 'x-node_env';
const token = 'x-node_env_node_env';
tmpl.token = token;
tmpl.style = style(tagName, token);
tmpl.token = 'x-node_env_node_env';
const style$$1 = document.createElement('style');
style$$1.type = 'text/css';
style$$1.dataset.token = 'x-node_env_node_env';
style$$1.textContent = style('x-node_env', 'x-node_env_node_env');
document.head.appendChild(style$$1);
}
class ClassAndTemplate extends Element {
connectedCallback() {
Expand All @@ -18,4 +20,4 @@ class ClassAndTemplate extends Element {
}
}
ClassAndTemplate.style = tmpl.style;
export default ClassAndTemplate;
export default ClassAndTemplate;

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ function tmpl($api, $cmp, $slotset, $ctx) {
}

if (style) {
const tagName = 'myns-relative_import';
const token = 'myns-relative_import_relative_import';
tmpl.token = token;
tmpl.style = style(tagName, token);
tmpl.token = 'myns-relative_import_relative_import';

const style$$1 = document.createElement('style');
style$$1.type = 'text/css';
style$$1.dataset.token = 'myns-relative_import_relative_import';
style$$1.textContent = style('myns-relative_import', 'myns-relative_import_relative_import');
document.head.appendChild(style$$1);
}

function test() {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ function tmpl($api, $cmp, $slotset, $ctx) {
})];
}
if (style) {
const tagName = 'x-foo';
const token = 'x-foo_foo';
tmpl.token = token;
tmpl.style = style(tagName, token);
tmpl.token = 'x-foo_foo';
const style$$1 = document.createElement('style');
style$$1.type = 'text/css';
style$$1.dataset.token = 'x-foo_foo';
style$$1.textContent = style('x-foo', 'x-foo_foo');
document.head.appendChild(style$$1);
}
class Metadata extends Element {
constructor(...args) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ function tmpl($api, $cmp, $slotset, $ctx) {
}

if (style) {
const tagName = 'x-foo';
const token = 'x-foo_foo';
tmpl.token = token;
tmpl.style = style(tagName, token);
tmpl.token = 'x-foo_foo';

const style$$1 = document.createElement('style');
style$$1.type = 'text/css';
style$$1.dataset.token = 'x-foo_foo';
style$$1.textContent = style('x-foo', 'x-foo_foo');
document.head.appendChild(style$$1);
}

const Test = 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ function tmpl($api, $cmp, $slotset, $ctx) {
}

if (style) {
const tagName = 'x-foo';
const token = 'x-foo_foo';
tmpl.token = token;
tmpl.style = style(tagName, token);
tmpl.token = 'x-foo_foo';

const style$$1 = document.createElement('style');
style$$1.type = 'text/css';
style$$1.dataset.token = 'x-foo_foo';
style$$1.textContent = style('x-foo', 'x-foo_foo');
document.head.appendChild(style$$1);
}

const Test = 1;
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 6 additions & 4 deletions packages/lwc-compiler/src/__tests__/fixtures/expected-styled.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ function tmpl($api, $cmp, $slotset, $ctx) {
}

if (style) {
const tagName = 'x-styled';
const token = 'x-styled_styled';
tmpl.token = 'x-styled_styled';

tmpl.token = token;
tmpl.style = style(tagName, token);
const style$$1 = document.createElement('style');
style$$1.type = 'text/css';
style$$1.dataset.token = 'x-styled_styled';
style$$1.textContent = style('x-styled', 'x-styled_styled');
document.head.appendChild(style$$1);
}

class Styled extends Element {
Expand Down
15 changes: 9 additions & 6 deletions packages/lwc-compiler/src/__tests__/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ describe('transform', () => {
`;

const expected = `
import style from './foo.css'
import stylesheet from './foo.css'
export default function tmpl($api, $cmp, $slotset, $ctx) {
const {
Expand All @@ -115,11 +115,14 @@ describe('transform', () => {
}, [api_text("Hello")])];
}
if (style) {
const tagName = 'x-foo';
const token = 'x-foo_foo';
tmpl.token = token;
tmpl.style = style(tagName, token);
if (stylesheet) {
tmpl.token = 'x-foo_foo';
const style = document.createElement('style');
style.type = 'text/css';
style.dataset.token = 'x-foo_foo'
style.textContent = stylesheet('x-foo', 'x-foo_foo');
document.head.appendChild(style);
}
`;

Expand Down
69 changes: 39 additions & 30 deletions packages/lwc-compiler/src/transformers/template.js
Original file line number Diff line number Diff line change
@@ -1,42 +1,51 @@
import * as path from 'path';
import compile from 'lwc-template-compiler';

export function getTemplateToken(filename, options) {
const templateId = path.basename(filename, path.extname(filename));
return `${options.moduleNamespace}-${options.moduleName}_${templateId}`;
}

/**
* Transforms a HTML template into module exporting a template function.
* The transform also add a style import for the default stylesheet associated with
* the template regardless if there is an actual style or not.
*/
export default function(src, options) {
const { filename, moduleName, moduleNamespace } = options;
const { code: template, metadata, warnings } = compile(src, {});
function attachStyleToTemplate(src, { moduleName, moduleNamespace, filename }) {
const templateFilename = path.basename(filename, path.extname(filename));

const fatalError = warnings.find(warning => warning.level === 'error');
if (fatalError) {
throw new Error(fatalError.message);
}
// Use the component tagname and a unique style token to scope the compiled
// styles to the component.
const tagName = `${moduleNamespace}-${moduleName}`;
const scopingToken = `${tagName}_${templateFilename}`;


const token = getTemplateToken(filename, options);
const cssName = path.basename(filename, path.extname(filename)) + '.css';

const code = [
`import style from './${cssName}'`,
return [
`import stylesheet from './${templateFilename}.css'`,
'',
template,
src,
'',
`if (style) {`,
` const tagName = '${moduleNamespace}-${moduleName}';`,
` const token = '${token}';`,

// The compiler resolves the style import to undefined if the stylesheet
// doesn't exists.
`if (stylesheet) {`,

// The engine picks the style token from the template during rendering to
// add the token to all generated elements.
` tmpl.token = '${scopingToken}';`,
``,
` tmpl.token = token;`,
` tmpl.style = style(tagName, token);`,

// Inject the component style in a new style tag the document head.
` const style = document.createElement('style');`,
` style.type = 'text/css';`,
` style.dataset.token = '${scopingToken}'`,
` style.textContent = stylesheet('${tagName}', '${scopingToken}');`,
` document.head.appendChild(style);`,
`}`,
].join('\n');
}

export default function(src, options) {
// Transform HTML template to javascript
const { code, metadata, warnings } = compile(src, {});

// Throw if a fatal error ocurred during the compilation
const error = warnings.find(warning => warning.level === 'error');
if (error) {
throw new Error(error.message);
}

return { code, metadata };
return {
code: attachStyleToTemplate(code, options),
metadata,
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<template>
<div id="child-div">Styles are not leaking</div>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { Element } from 'engine';

export default class XChild extends Element {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
:host {
display: block;
width: 300px;
height: 300px;
background: red;
}

div {
color: #00ff00;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<template>
<div id="parent-div">I am styled!</div>
<span id="dimensions">{dimensions}</span>

<hr>

<x-child></x-child>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Element, track } from 'engine';

export default class InjectStyle extends Element {
@track dimensions;

renderedCallback() {
if (this.dimensions === undefined) {
const { width, height } = this.getBoundingClientRect();
this.dimensions = `${width}x${height}`;
}
}
}
Loading

0 comments on commit 3b754f8

Please sign in to comment.