通常情况下,您不会直接与Svelte编译器交互,而是会使用打包器插件将其集成到您的构建系统中。Svelte团队最推荐并投入开发的打包器插件是vite-plugin-svelteSvelteKit框架提供了一个设置,利用vite-plugin-svelte构建应用程序,以及一个打包Svelte组件库的工具。Svelte Society维护了一个其他打包器插件的列表,用于像Rollup和Webpack这样的附加工具。

尽管如此,了解如何使用编译器是有用的,因为打包器插件通常会将编译器选项暴露给您。

编译

  1. function compile(
  2. source: string,
  3. options?: CompileOptions
  4. ): CompileResult;

这里是魔法发生的地方。svelte.compile获取您的组件源代码,并将其转换为导出类的JavaScript模块。

  1. import { compile } from 'svelte/compiler';
  2. const result = compile(source, {
  3. // 选项
  4. });

请参阅CompileOptions了解所有可用的选项。

返回的result对象包含组件的代码以及有用的元数据。

  1. const { js, css, ast, warnings, vars, stats } = compile(source);

请参阅CompileResult以获取编译结果的完整描述。

解析

  1. function parse(
  2. template: string,
  3. options?: ParserOptions
  4. ): Ast;

parse函数解析一个组件,只返回其抽象语法树。与使用generate: false选项编译不同,这将不会执行任何验证或其他分析,只会解析组件。请注意,返回的AST不被视为公共API,因此随时可能发生破坏性更改。

  1. import { parse } from 'svelte/compiler';
  2. const ast = parse(source, { filename: 'App.svelte' });

前处理

  1. function preprocess(
  2. source: string,
  3. preprocessor: PreprocessorGroup | PreprocessorGroup[],
  4. options?:
  5. | {
  6. filename?: string | undefined;
  7. }
  8. | undefined
  9. ): Promise<Processed>;

有许多官方和社区维护的预处理插件可供使用,以便您可以使用TypeScript、PostCSS、SCSS和Less等工具与Svelte一起使用。

您可以使用svelte.preprocess API编写自己的预处理器。

preprocess函数为任意转换组件源代码提供了方便的钩子。例如,它可以用来将<style lang="sass">块转换为普通CSS。

第一个参数是组件源代码。第二个是预处理器数组(如果您只有一个,也可以是单个预处理器),其中预处理器是一个具有必需的name的对象,以及可选的markupscriptstyle函数。

markup函数接收整个组件源文本,以及如果在第三个参数中指定了组件的filename

scriptstyle函数分别接收<script><style>元素的内容(content)以及整个组件源文本(markup)。除了filename,它们还得到元素属性的对象。

每个markupscriptstyle函数必须返回一个对象(或解析为对象的Promise),其中包含一个表示转换后的源代码的code属性。它们可以选择返回一个表示要监视更改的文件的dependencies数组,以及一个将转换映射回原始代码的map对象。scriptstyle预处理器可以选择返回一个属性记录,表示脚本/样式标签上的更新属性。

预处理器函数应尽可能返回一个map对象,否则调试将变得更加困难,因为堆栈跟踪无法正确链接到原始代码。

  1. import { preprocess } from 'svelte/compiler';
  2. import MagicString from 'magic-string';
  3. const { code } = await preprocess(
  4. source,
  5. {
  6. markup: ({ content, filename }) => {
  7. const pos = content.indexOf('foo');
  8. if (pos < 0) {
  9. return { code: content };
  10. }
  11. const s = new MagicString(content, { filename });
  12. s.overwrite(pos, pos + 3, 'bar', { storeName: true });
  13. return {
  14. code: s.toString(),
  15. map: s.generateMap()
  16. };
  17. },
  18. },
  19. {
  20. filename: 'App.svelte'
  21. }
  22. );

如果返回了dependencies数组,它将被包含在结果对象中。这被像vite-plugin-svelterollup-plugin-svelte这样的包使用,以监视附加文件的更改,在您的<style>标签具有@import(例如)的情况下。

preprocess-sass.js

  1. import { preprocess } from 'svelte/compiler';
  2. import MagicString from 'magic-string';
  3. import sass from 'sass';
  4. import { dirname } from 'path';
  5. const { code } = await preprocess(
  6. source,
  7. {
  8. name: 'my-fancy-preprocessor',
  9. markup: ({ content, filename }) => {
  10. // 当没有foo字符串时,原样返回代码
  11. const pos = content.indexOf('foo');
  12. if (pos < 0) {
  13. return;
  14. }
  15. // 使用MagicString替换foo为bar,它提供
  16. // 随着更改的代码一起的源映射
  17. const s = new MagicString(content, { filename });
  18. s.overwrite(pos, pos + 3, 'bar', { storeName: true });
  19. return {
  20. code: s.toString(),
  21. map: s.generateMap({ hires: true, file: filename })
  22. };
  23. },
  24. style: async ({ content, attributes, filename }) => {
  25. // 仅处理<style lang="sass">
  26. if (attributes.lang !== 'sass') return;
  27. const { css, stats } = await new Promise((resolve, reject) => {
  28. sass.render({
  29. file: filename,
  30. data: content,
  31. includePaths: [dirname(filename)]
  32. }, (err, result) => {
  33. if (err) reject(err);
  34. else resolve(result);
  35. });
  36. });
  37. // 从样式标签中移除lang属性
  38. delete attributes.lang;
  39. return {
  40. code: css.toString(),
  41. dependencies: stats.includedFiles,
  42. attributes
  43. };
  44. }
  45. },
  46. {
  47. filename: 'App.svelte'
  48. }
  49. );

可以一起使用多个预处理器。第一个的输出成为第二个的输入。在一个预处理器中,markup首先运行,然后是scriptstyle

在Svelte 3中,所有的markup函数首先运行,然后是所有的script,然后是所有的style预处理器。这个顺序在Svelte 4中改变了。

multiple-preprocessor.js

  1. import { preprocess } from 'svelte/compiler';
  2. const { code } = await preprocess(source, [
  3. {
  4. name: 'first preprocessor',
  5. markup: () => {
  6. console.log('this runs first');
  7. },
  8. script: () => {
  9. console.log('this runs second');
  10. },
  11. style: () => {
  12. console.log('this runs third');
  13. }
  14. },
  15. {
  16. name: 'second preprocessor',
  17. markup: () => {
  18. console.log('this runs fourth');
  19. },
  20. script: () => {
  21. console.log('this runs fifth');
  22. },
  23. style: () => {
  24. console.log('this runs sixth');
  25. }
  26. }
  27. ], {
  28. filename: 'App.svelte'
  29. });

multiple-preprocessor.ts

  1. import { preprocess } from 'svelte/compiler';
  2. const { code } = await preprocess(
  3. source,
  4. [
  5. {
  6. name: 'first preprocessor',
  7. markup: () => {
  8. console.log('this runs first');
  9. },
  10. script: () => {
  11. console.log('this runs second');
  12. },
  13. style: () => {
  14. console.log('this runs third');
  15. }
  16. },
  17. {
  18. name: 'second preprocessor',
  19. markup: () => {
  20. console.log('this runs fourth');
  21. },
  22. script: () => {
  23. console.log('this runs fifth');
  24. },
  25. style: () => {
  26. console.log('this runs sixth');
  27. }
  28. }
  29. ],
  30. {
  31. filename: 'App.svelte',
  32. }
  33. );

遍历

walk函数提供了一种方式,使用编译器自己的内置实例estree-walker来遍历由解析器生成的抽象语法树。

遍历器接受一个要遍历的抽象语法树和一个具有两个可选方法的对象:enterleave。对于每个节点,如果存在则调用enter。然后,除非在enter期间调用了this.skip(),否则遍历每个子节点, 然后在节点上调用leave

compiler-walk.js

  1. import { walk } from 'svelte/compiler';
  2. walk(ast, {
  3. enter(node, parent, prop, index) {
  4. do_something(node);
  5. if (should_skip_children(node)) {
  6. this.skip();
  7. }
  8. },
  9. leave(node, parent, prop, index) {
  10. do_something_else(node);
  11. }
  12. });

compiler-walk.ts

  1. import { walk } from 'svelte/compiler';
  2. walk(ast, {
  3. enter(node, parent, prop, index) {
  4. do_something(node);
  5. if (should_skip_children(node)) {
  6. this.skip();
  7. }
  8. },
  9. leave(node, parent, prop, index) {
  10. do_something_else(node);
  11. },
  12. });

VERSION

  1. const VERSION: string;

当前版本,如package.json中设置的。

  1. import { VERSION } from 'svelte/compiler';
  2. console.log(`running svelte version ${VERSION}`);

类型

CompileOptions

  1. interface CompileOptions {…}
  1. name?: string;
  • 默认 'Component'

设置结果JavaScript类的名称(尽管编译器会重命名它,以避免与作用域中的其他变量冲突)。它通常会从filename中推断出来。

  1. filename?: string;
  • 默认 null

用于调试提示和源映射。您的打包器插件将自动设置它。

  1. generate?: 'dom' | 'ssr' | false;
  • 默认 'dom'

如果为"dom",Svelte会发出一个用于挂载到DOM的JavaScript类。如果为"ssr",Svelte会发出一个带有适合服务器端渲染的render方法的对象。如果为false,则不返回JavaScript或CSS;只返回元数据。

  1. errorMode?: 'throw' | 'warn';
  • 默认 'throw'

如果为"throw",当编译发生错误时,Svelte会抛出异常。如果为"warn",Svelte将错误视为警告,并将它们添加到警告报告中。

  1. varsReport?: 'full' | 'strict' | false;
  • 默认 'strict'

如果为"strict",Svelte返回一个变量报告,其中只包含不是全局变量也不是内部变量的变量。如果为"full",Svelte返回一个包含所有检测到的变量的变量报告。如果为false,则不返回变量报告。

  1. sourcemap?: object | string;
  • 默认 null

将合并到最终输出源映射中的初始源映射。这通常是预处理器源映射。

  1. enableSourcemap?: EnableSourcemap;
  • 默认 true

如果为true,Svelte为组件生成源映射。使用具有jscss的对象进行更细粒度的源映射生成控制。

  1. outputFilename?: string;
  • 默认 null

用于您的JavaScript源映射。

  1. cssOutputFilename?: string;
  • 默认 null

用于您的CSS源映射。

  1. sveltePath?: string;
  • 默认 'svelte'

svelte包的位置。任何来自sveltesvelte/[module]的导入将相应地进行修改。

  1. dev?: boolean;
  • 默认 false

如果为true,会在组件中添加额外的代码,以便在开发期间执行运行时检查并提供调试信息。

  1. accessors?: boolean;
  • 默认 false

如果为true,将为组件的props创建getter和setter。如果为false,它们只会为只读导出值(即那些使用constclassfunction声明的值)创建。如果使用customElement: true编译,此选项默认为true

  1. immutable?: boolean;
  • 默认 false

如果为true,告诉编译器您承诺不会变异任何对象。这允许它在检查值是否已更改时更加保守。

  1. hydratable?: boolean;
  • 默认 false

如果为true,在生成DOM代码时,启用hydrate: true运行时选项,允许组件升级现有的DOM而不是从头开始创建新的DOM。在生成SSR代码时,这会在<head>元素中添加标记,以便hydration知道要替换哪些。

  1. legacy?: boolean;
  • 默认 false

如果为true,生成的代码将在不支持element.dataset等特性的IE9和IE10中工作。

  1. customElement?: boolean;
  • 默认 false

如果为true,告诉编译器生成自定义元素构造函数,而不是常规的Svelte组件。

  1. tag?: string;
  • 默认 null

一个string,告诉Svelte使用什么标签名注册自定义元素。它必须是至少包含一个连字符的小写字母数字字符串,例如"my-element"

  1. css?: 'injected' | 'external' | 'none' | boolean;
  • 'injected'(以前的true),样式将包含在JavaScript类中,并在实际渲染的组件的运行时注入。
  • 'external'(以前的false),CSS将返回在编译结果的css字段中。大多数Svelte打包器插件将此设置为'external',并使用静态生成的CSS以获得更好的性能,因为它将导致更小的JavaScript捆绑包,并且输出可以作为可缓存的.css文件提供。
  • 'none',完全避免样式,并且不生成CSS输出。
  1. loopGuardTimeout?: number;
  • 默认 0

一个number,告诉Svelte如果它阻塞线程超过loopGuardTimeout毫秒,就中断循环。这有助于防止无限循环。仅当dev: true时可用

  1. namespace?: string;
  • 默认 'html'

元素的命名空间;例如,"mathml""svg""foreign"

  1. cssHash?: CssHashGetter;
  • 默认 undefined

一个函数,它接受一个{ hash, css, name, filename }参数,并返回用作作用域CSS的类名的字符串。默认返回svelte-${hash(css)}

  1. preserveComments?: boolean;
  • 默认 false

如果为true,在服务器端渲染期间将保留您的HTML注释。默认情况下,它们会被剥离。

  1. preserveWhitespace?: boolean;
  • 默认 false

如果为true,元素内部和元素之间的空白将保持您输入的方式,而不是在可能的情况下删除或折叠为单个空格。

  1. discloseVersion?: boolean;
  • 默认 true

如果为true,在浏览器中通过添加到全局window.__svelte.v中存储的Set来公开Svelte主版本。

CompileResult

svelte/compiler返回的compile的形状

  1. interface CompileResult {…}
  1. js: {…}

组件编译生成的JavaScript代码

  1. code: string;

作为字符串的代码

  1. map: any;

一个源映射

  1. css: CssResult;

组件编译生成的CSS代码

  1. ast: Ast;

代表组件结构的抽象语法树

  1. warnings: Warning[];

在编译期间生成的警告对象数组。每个警告具有几个属性:

  • code是一个标识警告类别的字符串
  • message以人类可读的术语描述问题
  • startend,如果警告与特定位置相关,是具有行、列和字符属性的对象
  • frame,如果适用,是一个突出显示冒犯代码的字符串,并带有行号
  1. vars: Var[];

组件的声明数组,由生态系统中的工具(如我们的ESLint插件)用于推断更多信息

  1. stats: {
  2. timings: {
  3. total: number;
  4. };
  5. };

Svelte开发团队用于诊断编译器的对象。避免依赖它保持不变!

CssHashGetter

  1. type CssHashGetter = (args: {
  2. name: string;
  3. filename: string | undefined;
  4. css: string;
  5. hash: (input: string) => string;
  6. }) => string;

EnableSourcemap

  1. type EnableSourcemap =
  2. |
  3. boolean
  4. | { js: boolean; css: boolean };

MarkupPreprocessor

一个标记预处理器,它接受一段代码字符串,并返回一个处理过的版本。

  1. type MarkupPreprocessor = (options: {
  2. /**
  3. * The whole Svelte file content
  4. */
  5. content: string;
  6. /**
  7. * The filename of the Svelte file
  8. */
  9. filename?: string;
  10. }) => Processed | void | Promise<Processed | void>;

Preprocessor

一个脚本/样式预处理器,它接受一段代码字符串,并返回一个处理过的版本。

  1. type Preprocessor = (options: {
  2. /**
  3. * The script/style tag content
  4. */
  5. content: string;
  6. /**
  7. * The attributes on the script/style tag
  8. */
  9. attributes: Record<string, string | boolean>;
  10. /**
  11. * The whole Svelte file content
  12. */
  13. markup: string;
  14. /**
  15. * The filename of the Svelte file
  16. */
  17. filename?: string;
  18. }) => Processed | void | Promise<Processed | void>;

PreprocessorGroup

预处理器组是应用于Svelte文件的一组预处理器。

  1. interface PreprocessorGroup {…}
  1. name?: string;

预处理器的名称。在下一个主要版本中将是一个必需的选项

  1. markup?: MarkupPreprocessor;
  1. style?: Preprocessor;
  1. script?: Preprocessor;

Processed

预处理器运行的结果。如果预处理器没有返回结果,它假定代码未改变。

  1. interface Processed {…}
  1. code: string;

新代码

  1. map?: string | object;

一个源映射,映射回原始代码

  1. dependencies?: string[];

要监视更改的附加文件列表

  1. attributes?: Record<string, string | boolean>;

仅适用于脚本/样式预处理器:要在标签上设置的更新属性。如果未定义,属性保持不变。

  1. toString?: () => string;

SveltePreprocessor

实用类型,从预处理器组中提取预处理器的类型

  1. interface SveltePreprocessor<
  2. PreprocessorType extends keyof PreprocessorGroup,
  3. Options = any
  4. > {
  5. (options?: Options): Required<Pick<PreprocessorGroup, PreprocessorType>>;
  6. }