]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
feat: support component-level `compilerOptions` when using runtime compiler
authorEvan You <yyx990803@gmail.com>
Wed, 28 Apr 2021 15:35:59 +0000 (11:35 -0400)
committerEvan You <yyx990803@gmail.com>
Wed, 28 Apr 2021 15:40:16 +0000 (11:40 -0400)
- The `delimiters` component option is deprecated.
  Use `compilerOptions.delimiters` instead.

packages/runtime-core/src/component.ts
packages/runtime-core/src/componentOptions.ts
packages/runtime-core/src/index.ts
packages/vue/__tests__/runtimeCompilerOptions.spec.ts [new file with mode: 0644]

index ee817d6caa8108d46f8a366ce686dc9b89454091..54cf487bb45b3012e3e577562e9b0e9a364d725c 100644 (file)
@@ -578,6 +578,13 @@ function setupStatefulComponent(
         validateDirectiveName(names[i])
       }
     }
+    if (Component.compilerOptions && isRuntimeOnly()) {
+      warn(
+        `"compilerOptions" is only supported when using a build of Vue that ` +
+          `includes the runtime compiler. Since you are using a runtime-only ` +
+          `build, the options should be passed via your build tool config instead.`
+      )
+    }
   }
   // 0. create render proxy property access cache
   instance.accessCache = Object.create(null)
@@ -728,12 +735,19 @@ export function finishComponentSetup(
           startMeasure(instance, `compile`)
         }
         const { isCustomElement, compilerOptions } = instance.appContext.config
+        const {
+          delimiters,
+          compilerOptions: componentCompilerOptions
+        } = Component
         const finalCompilerOptions: CompilerOptions = extend(
-          {
-            isCustomElement: isCustomElement || NO,
-            delimiters: Component.delimiters
-          },
-          compilerOptions
+          extend(
+            {
+              isCustomElement,
+              delimiters
+            },
+            compilerOptions
+          ),
+          componentCompilerOptions
         )
         if (__COMPAT__) {
           // pass runtime compat config into the compiler
index 4222d063e1482329de7e8d4f42d2e214643cdfec..366ac379dcf8d2c8e40e2b1f0d9d2adcf209538d 100644 (file)
@@ -150,6 +150,9 @@ export interface ComponentOptionsBase<
   expose?: string[]
   serverPrefetch?(): Promise<any>
 
+  // Runtime compiler only -----------------------------------------------------
+  compilerOptions?: RuntimeCompilerOptions
+
   // Internal ------------------------------------------------------------------
 
   /**
@@ -203,6 +206,16 @@ export interface ComponentOptionsBase<
   __defaults?: Defaults
 }
 
+/**
+ * Subset of compiler options that makes sense for the runtime.
+ */
+export interface RuntimeCompilerOptions {
+  isCustomElement?: (tag: string) => boolean
+  whitespace?: 'preserve' | 'condense'
+  comments?: boolean
+  delimiters?: [string, string]
+}
+
 export type ComponentOptionsWithoutProps<
   Props = {},
   RawBindings = {},
@@ -446,7 +459,10 @@ interface LegacyOptions<
   renderTriggered?: DebuggerHook
   errorCaptured?: ErrorCapturedHook
 
-  // runtime compile only
+  /**
+   * runtime compile only
+   * @deprecated use `compilerOptions.delimiters` instead.
+   */
   delimiters?: [string, string]
 
   /**
index 3b4a16565fb6450b9fee575a092e78b8a217bf19..b4b63545364dc73d5e865d618616c121c3ee38f9 100644 (file)
@@ -179,7 +179,8 @@ export {
   ComponentOptionsBase,
   RenderFunction,
   MethodOptions,
-  ComputedOptions
+  ComputedOptions,
+  RuntimeCompilerOptions
 } from './componentOptions'
 export { EmitsOptions, ObjectEmitsOptions } from './componentEmits'
 export {
diff --git a/packages/vue/__tests__/runtimeCompilerOptions.spec.ts b/packages/vue/__tests__/runtimeCompilerOptions.spec.ts
new file mode 100644 (file)
index 0000000..3222462
--- /dev/null
@@ -0,0 +1,104 @@
+import { createApp } from 'vue'
+
+describe('config.compilerOptions', () => {
+  test('isCustomElement', () => {
+    const app = createApp({
+      template: `<foo/>`
+    })
+    app.config.compilerOptions.isCustomElement = (tag: string) => tag === 'foo'
+    const root = document.createElement('div')
+    app.mount(root)
+    expect(root.innerHTML).toBe('<foo></foo>')
+  })
+
+  test('comments', () => {
+    const app = createApp({
+      template: `<div/><!--test--><div/>`
+    })
+    app.config.compilerOptions.comments = true
+    // the comments option is only relevant in production mode
+    __DEV__ = false
+    const root = document.createElement('div')
+    app.mount(root)
+    expect(root.innerHTML).toBe('<div></div><!--test--><div></div>')
+    __DEV__ = true
+  })
+
+  test('whitespace', () => {
+    const app = createApp({
+      template: `<div><span/>\n  <span/></div>`
+    })
+    app.config.compilerOptions.whitespace = 'preserve'
+    const root = document.createElement('div')
+    app.mount(root)
+    expect(root.firstChild!.childNodes.length).toBe(3)
+    expect(root.firstChild!.childNodes[1].nodeType).toBe(Node.TEXT_NODE)
+  })
+
+  test('delimiters', () => {
+    const app = createApp({
+      data: () => ({ foo: 'hi' }),
+      template: `[[ foo ]]`
+    })
+    app.config.compilerOptions.delimiters = [`[[`, `]]`]
+    const root = document.createElement('div')
+    app.mount(root)
+    expect(root.textContent).toBe('hi')
+  })
+})
+
+describe('per-component compilerOptions', () => {
+  test('isCustomElement', () => {
+    const app = createApp({
+      template: `<foo/>`,
+      compilerOptions: {
+        isCustomElement: (tag: string) => tag === 'foo'
+      }
+    })
+    const root = document.createElement('div')
+    app.mount(root)
+    expect(root.innerHTML).toBe('<foo></foo>')
+  })
+
+  test('comments', () => {
+    const app = createApp({
+      template: `<div/><!--test--><div/>`,
+      compilerOptions: {
+        comments: true
+      }
+    })
+    app.config.compilerOptions.comments = false
+    // the comments option is only relevant in production mode
+    __DEV__ = false
+    const root = document.createElement('div')
+    app.mount(root)
+    expect(root.innerHTML).toBe('<div></div><!--test--><div></div>')
+    __DEV__ = true
+  })
+
+  test('whitespace', () => {
+    const app = createApp({
+      template: `<div><span/>\n  <span/></div>`,
+      compilerOptions: {
+        whitespace: 'preserve'
+      }
+    })
+    const root = document.createElement('div')
+    app.mount(root)
+    expect(root.firstChild!.childNodes.length).toBe(3)
+    expect(root.firstChild!.childNodes[1].nodeType).toBe(Node.TEXT_NODE)
+  })
+
+  test('delimiters', () => {
+    const app = createApp({
+      data: () => ({ foo: 'hi' }),
+      template: `[[ foo ]]`,
+      compilerOptions: {
+        delimiters: [`[[`, `]]`]
+      }
+    })
+    const root = document.createElement('div')
+    app.mount(root)
+    expect(root.textContent).toBe('hi')
+  })
+})