All files / server-renderer/src/helpers ssrCompile.ts

90.47% Statements 57/63
92.3% Branches 12/13
100% Functions 3/3
90.47% Lines 57/63

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 942x                                     2x   2x 173x 173x 173x   173x                 173x 173x 173x   173x 173x 173x 173x 173x 173x 173x 173x 173x 173x   173x 173x 173x   173x 173x 173x 173x 173x 173x 1051x 1051x 173x   173x 173x 70x 70x   103x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x     6x   103x 103x 103x 103x 103x 103x 103x 103x  
import {
  type ComponentInternalInstance,
  type ComponentOptions,
  warn,
} from 'vue'
import { compile } from '@vue/compiler-ssr'
import { NO, extend, generateCodeFrame, isFunction } from '@vue/shared'
import type { CompilerError, CompilerOptions } from '@vue/compiler-core'
import type { PushFn } from '../render'
 
import * as Vue from 'vue'
import * as helpers from '../internal'
 
type SSRRenderFunction = (
  context: any,
  push: PushFn,
  parentInstance: ComponentInternalInstance,
) => void
 
const compileCache: Record<string, SSRRenderFunction> = Object.create(null)
 
export function ssrCompile(
  template: string,
  instance: ComponentInternalInstance,
): SSRRenderFunction {
  // TODO: this branch should now work in ESM builds, enable it in a minor
  if (!__CJS__) {
    throw new Error(
      `On-the-fly template compilation is not supported in the ESM build of ` +
        `@vue/server-renderer. All templates must be pre-compiled into ` +
        `render functions.`,
    )
  }
 
  // TODO: This is copied from runtime-core/src/component.ts and should probably be refactored
  const Component = instance.type as ComponentOptions
  const { isCustomElement, compilerOptions } = instance.appContext.config
  const { delimiters, compilerOptions: componentCompilerOptions } = Component
 
  const finalCompilerOptions: CompilerOptions = extend(
    extend(
      {
        isCustomElement,
        delimiters,
      },
      compilerOptions,
    ),
    componentCompilerOptions,
  )
 
  finalCompilerOptions.isCustomElement =
    finalCompilerOptions.isCustomElement || NO
  finalCompilerOptions.isNativeTag = finalCompilerOptions.isNativeTag || NO
 
  const cacheKey = JSON.stringify(
    {
      template,
      compilerOptions: finalCompilerOptions,
    },
    (key, value) => {
      return isFunction(value) ? value.toString() : value
    },
  )
 
  const cached = compileCache[cacheKey]
  if (cached) {
    return cached
  }
 
  finalCompilerOptions.onError = (err: CompilerError) => {
    if (__DEV__) {
      const message = `[@vue/server-renderer] Template compilation error: ${err.message}`
      const codeFrame =
        err.loc &&
        generateCodeFrame(
          template as string,
          err.loc.start.offset,
          err.loc.end.offset,
        )
      warn(codeFrame ? `${message}\n${codeFrame}` : message)
    } else {
      throw err
    }
  }
 
  const { code } = compile(template, finalCompilerOptions)
  const requireMap = {
    vue: Vue,
    'vue/server-renderer': helpers,
  }
  const fakeRequire = (id: 'vue' | 'vue/server-renderer') => requireMap[id]
  return (compileCache[cacheKey] = Function('require', code)(fakeRequire))
}