compileTemplate.ts 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import {
  2. CompilerOptions,
  3. CodegenResult,
  4. CompilerError
  5. } from '@vue/compiler-core'
  6. import { RawSourceMap } from 'source-map'
  7. import { transformAssetUrl } from './templateTransformAssetUrl'
  8. import { transformSrcset } from './templateTransformSrcset'
  9. const consolidate = require('consolidate')
  10. export interface TemplateCompileResults {
  11. code: string
  12. source: string
  13. tips: string[]
  14. errors: (string | CompilerError)[]
  15. map?: RawSourceMap
  16. }
  17. export interface TemplateCompiler {
  18. compile(template: string, options: CompilerOptions): CodegenResult
  19. }
  20. export interface TemplateCompileOptions {
  21. source: string
  22. filename: string
  23. compiler: TemplateCompiler
  24. compilerOptions?: CompilerOptions
  25. preprocessLang?: string
  26. preprocessOptions?: any
  27. }
  28. function preprocess(
  29. { source, filename, preprocessOptions }: TemplateCompileOptions,
  30. preprocessor: any
  31. ): string {
  32. // Consolidate exposes a callback based API, but the callback is in fact
  33. // called synchronously for most templating engines. In our case, we have to
  34. // expose a synchronous API so that it is usable in Jest transforms (which
  35. // have to be sync because they are applied via Node.js require hooks)
  36. let res: any, err
  37. preprocessor.render(
  38. source,
  39. { filename, ...preprocessOptions },
  40. (_err: Error | null, _res: string) => {
  41. if (_err) err = _err
  42. res = _res
  43. }
  44. )
  45. if (err) throw err
  46. return res
  47. }
  48. export function compileTemplate(
  49. options: TemplateCompileOptions
  50. ): TemplateCompileResults {
  51. const { preprocessLang } = options
  52. const preprocessor = preprocessLang && consolidate[preprocessLang]
  53. if (preprocessor) {
  54. return doCompileTemplate({
  55. ...options,
  56. source: preprocess(options, preprocessor)
  57. })
  58. } else if (preprocessLang) {
  59. return {
  60. code: `export default function render() {}`,
  61. source: options.source,
  62. tips: [
  63. `Component ${
  64. options.filename
  65. } uses lang ${preprocessLang} for template. Please install the language preprocessor.`
  66. ],
  67. errors: [
  68. `Component ${
  69. options.filename
  70. } uses lang ${preprocessLang} for template, however it is not installed.`
  71. ]
  72. }
  73. } else {
  74. return doCompileTemplate(options)
  75. }
  76. }
  77. function doCompileTemplate({
  78. source,
  79. compiler,
  80. compilerOptions = {},
  81. filename
  82. }: TemplateCompileOptions): TemplateCompileResults {
  83. const errors: CompilerError[] = []
  84. const { code, map } = compiler.compile(source, {
  85. ...compilerOptions,
  86. filename,
  87. mode: 'module',
  88. sourceMap: true,
  89. nodeTransforms: [transformAssetUrl, transformSrcset],
  90. onError: e => errors.push(e)
  91. })
  92. return { code, source, errors, tips: [], map }
  93. }