add cssHash option (#6026)

* Allow to customize the css scope class

* Pass component name to scope class generator

* Move Stylesheet arguments into an object

* Refactor to cssHash

* Please the almighty linter

* pass hash function to cssHash

* update test

* document cssHash option

Co-authored-by: Christian Kaisermann <christian@kaisermann.me>
pull/6029/head
Rich Harris 5 years ago committed by GitHub
parent 5c8807e523
commit 2925a00eff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -74,6 +74,7 @@ The following options can be passed to the compiler. None are required:
| `customElement` | `false` | If `true`, tells the compiler to generate a custom element constructor instead of a regular Svelte component.
| `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"`.
| `css` | `true` | If `true`, styles will be included in the JavaScript class and injected at runtime. It's recommended that you set this to `false` and use the CSS that is statically generated, as it will result in smaller JavaScript bundles and better performance.
| `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)}`
| `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`**
| `preserveComments` | `false` | If `true`, your HTML comments will be preserved during server-side rendering. By default, they are stripped out.
| `preserveWhitespace` | `false` | If `true`, whitespace inside and between elements is kept as you typed it, rather than removed or collapsed to a single space where possible.

@ -133,12 +133,14 @@ export default class Component {
this.locate = getLocator(this.source, { offsetLine: 1 });
// styles
this.stylesheet = new Stylesheet(
this.stylesheet = new Stylesheet({
source,
ast,
compile_options.filename,
compile_options.dev
);
filename: compile_options.filename,
component_name: name,
dev: compile_options.dev,
get_css_hash: compile_options.cssHash
});
this.stylesheet.validate(this);
this.component_options = process_component_options(

@ -2,7 +2,7 @@ import MagicString from 'magic-string';
import { walk } from 'estree-walker';
import Selector from './Selector';
import Element from '../nodes/Element';
import { Ast } from '../../interfaces';
import { Ast, CssHashGetter } from '../../interfaces';
import Component from '../Component';
import { CssNode } from './interfaces';
import hash from '../utils/hash';
@ -275,6 +275,10 @@ class Atrule {
}
}
const get_default_css_hash: CssHashGetter = ({ css, hash }) => {
return `svelte-${hash(css)}`;
};
export default class Stylesheet {
source: string;
ast: Ast;
@ -289,14 +293,33 @@ export default class Stylesheet {
nodes_with_css_class: Set<CssNode> = new Set();
constructor(source: string, ast: Ast, filename: string, dev: boolean) {
constructor({
source,
ast,
component_name,
filename,
dev,
get_css_hash = get_default_css_hash
}: {
source: string;
ast: Ast;
filename: string | undefined;
component_name: string | undefined;
dev: boolean;
get_css_hash: CssHashGetter;
}) {
this.source = source;
this.ast = ast;
this.filename = filename;
this.dev = dev;
if (ast.css && ast.css.children.length) {
this.id = `svelte-${hash(ast.css.content.styles)}`;
this.id = get_css_hash({
filename,
name: component_name,
css: ast.css.content.styles,
hash
});
this.has_styles = true;

@ -28,7 +28,8 @@ const valid_options = [
'css',
'loopGuardTimeout',
'preserveComments',
'preserveWhitespace'
'preserveWhitespace',
'cssHash'
];
function validate_options(options: CompileOptions, warnings: Warning[]) {

@ -104,6 +104,13 @@ export interface Warning {
export type ModuleFormat = 'esm' | 'cjs';
export type CssHashGetter = (args: {
name: string;
filename: string | undefined;
css: string;
hash: (input: string) => string;
}) => string;
export interface CompileOptions {
format?: ModuleFormat;
name?: string;
@ -125,6 +132,7 @@ export interface CompileOptions {
css?: boolean;
loopGuardTimeout?: number;
namespace?: string;
cssHash?: CssHashGetter;
preserveComments?: boolean;
preserveWhitespace?: boolean;
@ -166,7 +174,7 @@ export interface Var {
imported?: boolean;
}
export interface CssResult {
export interface CssResult {
code: string;
map: SourceMap;
}

@ -0,0 +1,12 @@
export default {
compileOptions: {
filename: 'src/components/FooSwitcher.svelte',
cssHash({ hash, css, name, filename }) {
const minFilename = filename
.split('/')
.map(i => i.charAt(0).toLowerCase())
.join('');
return `sv-${name}-${minFilename}-${hash(css)}`;
}
}
};

@ -0,0 +1 @@
div.sv-FooSwitcher-scf-bzh57p{color:red}

@ -0,0 +1,7 @@
<div>red</div>
<style>
div {
color: red;
}
</style>
Loading…
Cancel
Save