Skip to content

Commit 773dedf

Browse files
author
Maximiliano Ruani
authored
[feat] Compiler option css: 'none' support (#7914)
1 parent b05b684 commit 773dedf

File tree

9 files changed

+80
-5
lines changed

9 files changed

+80
-5
lines changed

site/content/docs/05-compile-time.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ The following options can be passed to the compiler. None are required:
7373
| `accessors` | `false` | If `true`, getters and setters will be created for the component's props. If `false`, they will only be created for readonly exported values (i.e. those declared with `const`, `class` and `function`). If compiling with `customElement: true` this option defaults to `true`.
7474
| `customElement` | `false` | If `true`, tells the compiler to generate a custom element constructor instead of a regular Svelte component.
7575
| `tag` | `null` | A `string` that tells Svelte what tag name to register the custom element with. It must be a lowercase alphanumeric string with at least one hyphen, e.g. `"my-element"`.
76-
| `css` | `true` | If `true`, styles will be included in the JavaScript class and injected at runtime for the components actually rendered. If `false`, the CSS will be returned in the `css` field of the compilation result. Most Svelte bundler plugins will set this to `false` and use the CSS that is statically generated for better performance, as it will result in smaller JavaScript bundles and the output can be served as cacheable `.css` files.
76+
| `css` | `'injected'` | If `'injected'` (formerly `true`), styles will be included in the JavaScript class and injected at runtime for the components actually rendered. If `'external'` (formerly `false`), the CSS will be returned in the `css` field of the compilation result. Most Svelte bundler plugins will set this to `'external'` and use the CSS that is statically generated for better performance, as it will result in smaller JavaScript bundles and the output can be served as cacheable `.css` files. If `'none'`, styles are completely avoided and no CSS output is generated.
7777
| `cssHash` | See right | A function that takes a `{ hash, css, name, filename }` argument and returns the string that is used as a classname for scoped CSS. It defaults to returning `svelte-${hash(css)}`
7878
| `loopGuardTimeout` | 0 | A `number` that tells Svelte to break the loop if it blocks the thread for more than `loopGuardTimeout` ms. This is useful to prevent infinite loops. **Only available when `dev: true`**
7979
| `preserveComments` | `false` | If `true`, your HTML comments will be preserved during server-side rendering. By default, they are stripped out.

src/compiler/compile/index.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,19 @@ const valid_options = [
3535
'cssHash'
3636
];
3737

38+
const valid_css_values = [
39+
true,
40+
false,
41+
'injected',
42+
'external',
43+
'none'
44+
];
45+
3846
const regex_valid_identifier = /^[a-zA-Z_$][a-zA-Z_$0-9]*$/;
3947
const regex_starts_with_lowercase_character = /^[a-z]/;
4048

4149
function validate_options(options: CompileOptions, warnings: Warning[]) {
42-
const { name, filename, loopGuardTimeout, dev, namespace } = options;
50+
const { name, filename, loopGuardTimeout, dev, namespace, css } = options;
4351

4452
Object.keys(options).forEach(key => {
4553
if (!valid_options.includes(key)) {
@@ -75,6 +83,21 @@ function validate_options(options: CompileOptions, warnings: Warning[]) {
7583
});
7684
}
7785

86+
if (valid_css_values.indexOf(css) === -1) {
87+
throw new Error(`options.css must be true, false, 'injected', 'external', or 'none' (got '${css}')`);
88+
}
89+
90+
if (css === true || css === false) {
91+
options.css = css === true ? 'injected' : 'external';
92+
const message = `options.css as a boolean is deprecated. Use '${options.css}' instead of ${css}.`;
93+
warnings.push({
94+
code: 'options-css-boolean-deprecated',
95+
message,
96+
filename,
97+
toString: () => message
98+
});
99+
}
100+
78101
if (namespace && valid_namespaces.indexOf(namespace) === -1) {
79102
const match = fuzzymatch(namespace, valid_namespaces);
80103
if (match) {
@@ -86,7 +109,7 @@ function validate_options(options: CompileOptions, warnings: Warning[]) {
86109
}
87110

88111
export default function compile(source: string, options: CompileOptions = {}) {
89-
options = Object.assign({ generate: 'dom', dev: false, enableSourcemap: true }, options);
112+
options = Object.assign({ generate: 'dom', dev: false, enableSourcemap: true, css: 'injected' }, options);
90113

91114
const stats = new Stats();
92115
const warnings = [];

src/compiler/compile/render_dom/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export default function dom(
5454
const should_add_css = (
5555
!options.customElement &&
5656
!!styles &&
57-
options.css !== false
57+
options.css === 'injected'
5858
);
5959

6060
if (should_add_css) {

src/compiler/interfaces.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ export interface CompileOptions {
179179
legacy?: boolean;
180180
customElement?: boolean;
181181
tag?: string;
182-
css?: boolean;
182+
css?: 'injected' | 'external' | 'none' | boolean;
183183
loopGuardTimeout?: number;
184184
namespace?: string;
185185
cssHash?: CssHashGetter;
@@ -191,6 +191,7 @@ export interface CompileOptions {
191191
export interface ParserOptions {
192192
filename?: string;
193193
customElement?: boolean;
194+
css?: 'injected' | 'external' | 'none' | boolean;
194195
}
195196

196197
export interface Visitor {

src/compiler/parse/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export class Parser {
2121
readonly template: string;
2222
readonly filename?: string;
2323
readonly customElement: boolean;
24+
readonly css_mode: 'injected' | 'external' | 'none' | boolean;
2425

2526
index = 0;
2627
stack: TemplateNode[] = [];
@@ -39,6 +40,7 @@ export class Parser {
3940
this.template = template.trimRight();
4041
this.filename = options.filename;
4142
this.customElement = options.customElement;
43+
this.css_mode = options.css;
4244

4345
this.html = {
4446
start: null,

src/compiler/parse/read/style.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ export default function read_style(parser: Parser, start: number, attributes: No
1919

2020
const content_end = parser.index;
2121

22+
// discard styles when css is disabled
23+
if (parser.css_mode === 'none') {
24+
parser.read(regex_closing_style_tag);
25+
return null;
26+
}
27+
2228
let ast;
2329

2430
try {
@@ -71,6 +77,7 @@ export default function read_style(parser: Parser, start: number, attributes: No
7177
});
7278

7379
parser.read(regex_closing_style_tag);
80+
7481
const end = parser.index;
7582

7683
return {
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<div>foo</div>
2+
3+
<style>
4+
div {
5+
color: red;
6+
}
7+
</style>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"css": "none"
3+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"html": {
3+
"start": 0,
4+
"end": 14,
5+
"type": "Fragment",
6+
"children": [
7+
{
8+
"start": 0,
9+
"end": 14,
10+
"type": "Element",
11+
"name": "div",
12+
"attributes": [],
13+
"children": [
14+
{
15+
"start": 5,
16+
"end": 8,
17+
"type": "Text",
18+
"raw": "foo",
19+
"data": "foo"
20+
}
21+
]
22+
},
23+
{
24+
"start": 14,
25+
"end": 16,
26+
"type": "Text",
27+
"raw": "\n\n",
28+
"data": "\n\n"
29+
}
30+
]
31+
}
32+
}

0 commit comments

Comments
 (0)