Jelajahi Sumber

refactor: ensure ssr branches are included in esm-bundler build

Evan You 4 tahun lalu
induk
melakukan
87c86e4cc2

+ 1 - 0
jest.config.js

@@ -11,6 +11,7 @@ module.exports = {
     __ESM_BUNDLER__: true,
     __ESM_BROWSER__: false,
     __NODE_JS__: true,
+    __SSR__: true,
     __FEATURE_OPTIONS_API__: true,
     __FEATURE_SUSPENSE__: true,
     __FEATURE_PROD_DEVTOOLS__: false,

+ 1 - 0
packages/global.d.ts

@@ -8,6 +8,7 @@ declare var __GLOBAL__: boolean
 declare var __ESM_BUNDLER__: boolean
 declare var __ESM_BROWSER__: boolean
 declare var __NODE_JS__: boolean
+declare var __SSR__: boolean
 declare var __COMMIT__: string
 declare var __VERSION__: string
 declare var __COMPAT__: boolean

+ 1 - 1
packages/runtime-core/src/apiAsyncComponent.ts

@@ -141,7 +141,7 @@ export function defineAsyncComponent<
       // suspense-controlled or SSR.
       if (
         (__FEATURE_SUSPENSE__ && suspensible && instance.suspense) ||
-        (__NODE_JS__ && isInSSRComponentSetup)
+        (__SSR__ && isInSSRComponentSetup)
       ) {
         return load()
           .then(comp => {

+ 1 - 1
packages/runtime-core/src/apiWatch.ts

@@ -280,7 +280,7 @@ function doWatch(
 
   // in SSR there is no need to setup an actual effect, and it should be noop
   // unless it's eager
-  if (__NODE_JS__ && isInSSRComponentSetup) {
+  if (__SSR__ && isInSSRComponentSetup) {
     // we will also not call the invalidate callback (+ runner is not set up)
     onInvalidate = NOOP
     if (!cb) {

+ 6 - 13
packages/runtime-core/src/component.ts

@@ -678,7 +678,7 @@ export function handleSetupResult(
 ) {
   if (isFunction(setupResult)) {
     // setup returned an inline render function
-    if (__NODE_JS__ && (instance.type as ComponentOptions).__ssrInlineRender) {
+    if (__SSR__ && (instance.type as ComponentOptions).__ssrInlineRender) {
       // when the function's name is `ssrRender` (compiled by SFC inline mode),
       // set it as ssrRender instead.
       instance.ssrRender = setupResult
@@ -751,18 +751,11 @@ export function finishComponentSetup(
   }
 
   // template / render function normalization
-  if (__NODE_JS__ && isSSR) {
-    // 1. the render function may already exist, returned by `setup`
-    // 2. otherwise try to use the `Component.render`
-    // 3. if the component doesn't have a render function,
-    //    set `instance.render` to NOOP so that it can inherit the render
-    //    function from mixins/extend
-    instance.render = (instance.render ||
-      Component.render ||
-      NOOP) as InternalRenderFunction
-  } else if (!instance.render) {
-    // could be set from setup()
-    if (compile && !Component.render) {
+  // could be already set when returned from setup()
+  if (!instance.render) {
+    // only do on-the-fly compile if not in SSR - SSR on-the-fly compliation
+    // is done by server-renderer
+    if (!isSSR && compile && !Component.render) {
       const template =
         (__COMPAT__ &&
           instance.vnode.props &&

+ 1 - 3
packages/runtime-core/src/index.ts

@@ -315,9 +315,7 @@ const _ssrUtils = {
  * SSR utils for \@vue/server-renderer. Only exposed in cjs builds.
  * @internal
  */
-export const ssrUtils = (
-  __NODE_JS__ || __ESM_BUNDLER__ ? _ssrUtils : null
-) as typeof _ssrUtils
+export const ssrUtils = (__SSR__ ? _ssrUtils : null) as typeof _ssrUtils
 
 // 2.x COMPAT ------------------------------------------------------------------
 

+ 3 - 2
packages/runtime-dom/src/directives/vModel.ts

@@ -303,8 +303,9 @@ function callModelHook(
   fn && fn(el, binding, vnode, prevVNode)
 }
 
-// SSR vnode transforms
-if (__NODE_JS__) {
+// SSR vnode transforms, only used when user includes client-oriented render
+// function in SSR
+export function initVModelForSSR() {
   vModelText.getSSRProps = ({ value }) => ({ value })
 
   vModelRadio.getSSRProps = ({ value }, vnode) => {

+ 7 - 5
packages/runtime-dom/src/directives/vShow.ts

@@ -40,14 +40,16 @@ export const vShow: ObjectDirective<VShowElement> = {
   }
 }
 
-if (__NODE_JS__) {
+function setDisplay(el: VShowElement, value: unknown): void {
+  el.style.display = value ? el._vod : 'none'
+}
+
+// SSR vnode transforms, only used when user includes client-oriented render
+// function in SSR
+export function initVShowForSSR() {
   vShow.getSSRProps = ({ value }) => {
     if (!value) {
       return { style: { display: 'none' } }
     }
   }
 }
-
-function setDisplay(el: VShowElement, value: unknown): void {
-  el.style.display = value ? el._vod : 'none'
-}

+ 26 - 1
packages/runtime-dom/src/index.ts

@@ -15,7 +15,14 @@ import {
 import { nodeOps } from './nodeOps'
 import { patchProp } from './patchProp'
 // Importing from the compiler, will be tree-shaken in prod
-import { isFunction, isString, isHTMLTag, isSVGTag, extend } from '@vue/shared'
+import {
+  isFunction,
+  isString,
+  isHTMLTag,
+  isSVGTag,
+  extend,
+  NOOP
+} from '@vue/shared'
 
 declare module '@vue/reactivity' {
   export interface RefUnwrapBailTypes {
@@ -225,6 +232,24 @@ export {
 export { withModifiers, withKeys } from './directives/vOn'
 export { vShow } from './directives/vShow'
 
+import { initVModelForSSR } from './directives/vModel'
+import { initVShowForSSR } from './directives/vShow'
+
+let ssrDirectiveInitialized = false
+
+/**
+ * @internal
+ */
+export const initDirectivesForSSR = __SSR__
+  ? () => {
+      if (!ssrDirectiveInitialized) {
+        ssrDirectiveInitialized = true
+        initVModelForSSR()
+        initVShowForSSR()
+      }
+    }
+  : NOOP
+
 // re-export everything from core
 // h, Component, reactivity API, nextTick, flags & types
 export * from '@vue/runtime-core'

+ 3 - 0
packages/server-renderer/src/index.ts

@@ -1,3 +1,6 @@
+import { initDirectivesForSSR } from 'vue'
+initDirectivesForSSR()
+
 // public
 export { SSRContext } from './render'
 export { renderToString } from './renderToString'

+ 2 - 0
rollup.config.js

@@ -242,6 +242,8 @@ function createReplacePlugin(
     __ESM_BROWSER__: isBrowserESMBuild,
     // is targeting Node (SSR)?
     __NODE_JS__: isNodeBuild,
+    // need SSR-specific branches?
+    __SSR__: isNodeBuild || isBundlerESMBuild,
 
     // for compiler-sfc browser build inlined deps
     ...(isBrowserESMBuild