Evan You 9 lat temu
rodzic
commit
60cf3b8e00

+ 3 - 3
src/compiler/codegen/index.js

@@ -141,11 +141,11 @@ function genIfConditions (
 
   const condition = conditions.shift()
   if (condition.exp) {
-    return `(${condition.exp})?${
+    return `(${condition.exp})?(${
       genTernaryExp(condition.block)
-    }:${
+    }):(${
       genIfConditions(conditions, state, altGen, altEmpty)
-    }`
+    })`
   } else {
     return `${genTernaryExp(condition.block)}`
   }

+ 48 - 20
src/server/optimizing-compiler/codegen.js

@@ -13,19 +13,27 @@ import {
   genChildren,
   CodegenState
 } from 'compiler/codegen/index'
+
+import {
+  genAttrSegments,
+  genDOMPropSegments,
+  applyModelTransform
+} from './modules'
+
 import { optimizability } from './optimizer'
-import type { CodegenResult } from 'compiler/codegen/index'
 
-// segment types
-const RAW = 0
-const INTERPOLATION = 1
-const EXPRESSION = 2
+import type { CodegenResult } from 'compiler/codegen/index'
 
-type StringSegment = {
+export type StringSegment = {
   type: number;
   value: string;
 };
 
+// segment types
+export const RAW = 0
+export const INTERPOLATION = 1
+export const EXPRESSION = 2
+
 export function generate (
   ast: ASTElement | void,
   options: CompilerOptions
@@ -125,17 +133,6 @@ function elementToSegments (el, state): Array<StringSegment> {
     }]
   }
 
-  // let binding
-  // // v-show
-  // if ((binding = el.attrsMap['v-show'])) {
-
-  // }
-
-  // // v-model
-  // if ((binding = el.attrsMap['v-model'])) {
-
-  // }
-
   const openSegments = elementToOpenTagSegments(el, state)
   const childrenSegments = childrenToSegments(el, state)
   const { isUnaryTag } = state.options
@@ -146,9 +143,40 @@ function elementToSegments (el, state): Array<StringSegment> {
 }
 
 function elementToOpenTagSegments (el, state): Array<StringSegment> {
-  // TODO: handle v-show, v-html & v-text
-  // TODO: handle attrs/props/styles/classes
-  return [{ type: RAW, value: `<${el.tag}>` }]
+  applyModelTransform(el, state)
+  let binding
+  const segments = [{ type: RAW, value: `<${el.tag}` }]
+  // attrs
+  if (el.attrs) {
+    segments.push.apply(segments, genAttrSegments(el.attrs))
+  }
+  // domProps
+  if (el.props) {
+    segments.push.apply(segments, genDOMPropSegments(el.props, el.attrs))
+  }
+  // v-bind="object"
+  if ((binding = el.attrsMap['v-bind'])) {
+    segments.push({ type: EXPRESSION, value: `_ssrAttrs(${binding})` })
+  }
+  // v-bind.prop="object"
+  if ((binding = el.attrsMap['v-bind.prop'])) {
+    segments.push({ type: EXPRESSION, value: `_ssrDOMProps(${binding})` })
+  }
+  // class
+  if (el.staticClass || el.classBinding) {
+    if (el.staticClass && !el.classBinding) {
+      segments.push({ type: RAW, value: ` class=${el.staticClass}` })
+    } else {
+      // TODO
+    }
+  }
+  // style & v-show
+  if (el.staticStyle || el.styleBinding) {
+    // TODO
+  }
+  // console.log(segments)
+  segments.push({ type: RAW, value: `>` })
+  return segments
 }
 
 function childrenToSegments (el, state): Array<StringSegment> {

+ 70 - 0
src/server/optimizing-compiler/modules.js

@@ -0,0 +1,70 @@
+/* @flow */
+
+import {
+  RAW,
+  // INTERPOLATION,
+  EXPRESSION
+} from './codegen'
+
+import {
+  propsToAttrMap,
+  isRenderableAttr
+} from 'web/server/util'
+
+import type { StringSegment } from './codegen'
+import type { CodegenState } from 'compiler/codegen/index'
+
+type Attr = { name: string; value: string };
+
+const plainStringRE = /^"(?:[^"\\]|\\.)*"$|^'(?:[^'\\]|\\.)*'$/
+
+// let the model AST transform translate v-model into appropriate
+// props bindings
+export function applyModelTransform (el: ASTElement, state: CodegenState) {
+  if (el.directives) {
+    for (let i = 0; i < el.directives.length; i++) {
+      const dir = el.directives[i]
+      if (dir.name === 'model') {
+        state.directives.model(el, dir, state.warn)
+        break
+      }
+    }
+  }
+}
+
+export function genAttrSegments (
+  attrs: Array<Attr>
+): Array<StringSegment> {
+  return attrs.map(({ name, value }) => genAttrSegment(name, value))
+}
+
+export function genDOMPropSegments (
+  props: Array<Attr>,
+  attrs: ?Array<Attr>
+): Array<StringSegment> {
+  const segments = []
+  props.forEach(({ name, value }) => {
+    name = propsToAttrMap[name] || name.toLowerCase()
+    if (isRenderableAttr(name) &&
+      !(attrs && attrs.some(a => a.name === name))
+    ) {
+      segments.push(genAttrSegment(name, value))
+    }
+  })
+  return segments
+}
+
+function genAttrSegment (name: string, value: string): StringSegment {
+  if (plainStringRE.test(value)) {
+    // TODO attr type checks
+    return {
+      type: RAW,
+      value: ` ${name}=${value}`
+    }
+  } else {
+    return {
+      type: EXPRESSION,
+      value: `_ssrAttr(${JSON.stringify(name)},${value})`
+    }
+  }
+}

+ 2 - 0
src/server/optimizing-compiler/runtime-helpers.js

@@ -2,6 +2,7 @@
 
 import { escape } from 'he'
 import { isObject } from 'shared/util'
+import { renderAttr } from 'web/server/modules/attrs'
 
 export function installSSRHelpers (vm: Component) {
   let Ctor = vm.constructor
@@ -12,6 +13,7 @@ export function installSSRHelpers (vm: Component) {
     Ctor.prototype._ssrNode = createStringNode
     Ctor.prototype._ssrList = createStringList
     Ctor.prototype._ssrEscape = escape
+    Ctor.prototype._ssrAttr = renderAttr
   }
 }