Skip to content

Commit 17f5cbd

Browse files
committed
feature: package vue-ssr-jit
1 parent ff579f0 commit 17f5cbd

File tree

4 files changed

+22673
-102
lines changed

4 files changed

+22673
-102
lines changed

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"dev:weex:compiler": "rollup -w -c scripts/config.js --environment TARGET:weex-compiler ",
2727
"build": "node scripts/build.js",
2828
"build:ssr": "npm run build -- web-runtime-cjs,web-server-renderer",
29+
"build:ssr-jit": "rollup -w -c scripts/config.js --environment TARGET:vue-ssr-jit-prod",
2930
"build:weex": "npm run build -- weex",
3031
"test": "npm run lint && flow check && npm run test:types && npm run test:cover && npm run test:e2e -- --env phantomjs && npm run test:ssr && npm run test:weex",
3132
"test:unit": "karma start test/unit/karma.unit.config.js",

packages/vue-ssr-jit/README.md

+45-92
Original file line numberDiff line numberDiff line change
@@ -1,116 +1,69 @@
11
# vue-ssr-jit
22

3-
vue ssr 运行时优化
4-
5-
## 安装
6-
```
7-
npm install --save-dev vue-ssr-jit
8-
```
9-
10-
## 使用
11-
> vue 最低版本为 2.6.x ,vue-loader 最低版本为 15.x
12-
13-
```js
14-
/*
15-
* 将官方 ssr 渲染器替换成如下渲染器
16-
*/
17-
const { createBundleRenderer } = require('vue-ssr')
3+
A just in time compilation technique for server-side rendering. Use the Diff algorithm to derive dynamic and static nodes at runtime, and then generate and run a new rendering tree to dramatically increase rendering performance.
4+
5+
The following vue template:
6+
```html
7+
<template>
8+
<div>
9+
<router-link to="/">{{name}}</router-link>
10+
<router-view></router-view>
11+
</div>
12+
</template>
13+
14+
<script>
15+
export default {
16+
data() {
17+
return {
18+
name: 'vue-ssr-jit'
19+
}
20+
}
21+
}
22+
</script>
1823
```
1924

20-
如下为要被替换的官方渲染器
25+
Code generated by the official compiler:
2126
```js
22-
const { createBundleRenderer } = require('vue-server-renderer')
27+
_c("div", [
28+
_c("router-link", {attrs: { to: "/" }}, [
29+
_vm._v(_vm._s(_vm.name))
30+
]),
31+
_c("router-view")
32+
], 1)
2333
```
2434

25-
vue-loader webpack 配置 修改如下,添加自定义 compiler
35+
Code generated using vue-ssr-jit:
2636
```js
27-
const compiler = require('vue-ssr/compiler')
28-
29-
...
30-
31-
{
32-
test: /\.vue$/,
33-
loader: 'vue-loader',
34-
options: {
35-
compiler,
36-
}
37-
}
37+
_c("div", [
38+
_vm._ssrNode(
39+
"<a href=\"/\" class=\"router-link-active\">vue-ssr-jit</a>"
40+
),
41+
_c("router-view")
42+
], 1);
3843
```
3944

40-
41-
#### entry-server.js 写法一
42-
适用于在实例化前就需要载入数据的应用
45+
## Use
4346

4447
```js
45-
/* entry-server.js */
46-
47-
import { createApp } from './app'
48-
49-
/*
50-
* base 方法用于导出一个静态的 vue 实例
51-
*/
52-
export const base = () => {
53-
const {app} = createApp()
54-
return Promise.resolve(app)
55-
}
56-
57-
/*
58-
* 默认导出的 vue 实例
59-
*/
60-
export default (context) => {
61-
return base().then((app) => {
62-
return context.initSyncData(app.$store, context.payload).then(() => {
63-
context.state = app.$store.state
64-
return app
65-
})
66-
})
67-
}
48+
npm install --save vue-ssr-jit
6849
```
6950

70-
#### entry-server.js 写法二
71-
适用于在渲染过程中载入数据的应用
72-
7351
```js
74-
/* entry-server.js */
75-
76-
import { createApp } from './app'
77-
78-
/*
79-
* 直接导出 Vue 实例,渲染器自动根据动静配置选择是否载入 serverPrefetch
80-
*/
81-
export default (context) => {
82-
const {app} = createApp()
83-
return Promise.resolve(app)
84-
}
52+
const { createBundleRenderer } = require('vue-ssr-jit')
8553
```
8654

87-
## 注意
55+
`createBundleRenderer` is consistent with the official function interface of the same name, see the [vue ssr guide](https://ssr.vuejs.org/api/#createbundlerenderer)
8856

89-
ssr 推导需要取一份静态实例作为优化基准,在静态实例服务端渲染周期内不要出现与特定用户相关的代码操作,类似如下操作不建议使用,除非你确定此数据与用户无关
57+
It is recommended to use `serverPrefetch` for prefetching data, and it is also supported to use `asyncData` for prefetching data, see [demo](https://github.com/SmallComfort/vue-ssr-jit-demo)
9058

91-
```js
92-
data() {
93-
let cookie = cookie
94-
try {
95-
cookie = document.cookie
96-
} catch(e) {
97-
// 以某种方式取到了后台 cookie
98-
cookie = global.xxx.cookie
99-
}
100-
return {
101-
cookie
102-
}
103-
},
104-
```
59+
## Implementation principle
10560

106-
cookie 在 serverPrefetch 方法内可被使用,以及在服务端渲染周期结束后也可以被使用,例如:`mounted``updated` 等等
61+
[Vue SSR Just In Time Compilation](/PRINCIPLE.md)
10762

108-
可以使用如下插件检测页面代码是否在服务端渲染周期内使用了 cookie
109-
```js
110-
/* entry-client.js*/
111-
import ssrSafety from 'vue-ssr/ssr-safety'
63+
## Be careful
11264

113-
Vue.use(ssrSafety)
65+
This technology is currently in the experimental stage.
11466

115-
```
67+
## License
11668

69+
[MIT](http://opensource.org/licenses/MIT)

packages/vue-ssr-jit/build.dev.js

+34-10
Original file line numberDiff line numberDiff line change
@@ -6575,7 +6575,6 @@ function renderSSRStyle (
65756575

65766576
/* */
65776577

6578-
65796578
var isJS = function (file) { return /\.js(\?[^.]+)?$/.test(file); };
65806579

65816580
var isCSS = function (file) { return /\.css(\?[^.]+)?$/.test(file); };
@@ -6695,7 +6694,7 @@ function getVNodeRenderAst(ast) {
66956694
noScope: true,
66966695
ReturnStatement: function ReturnStatement(path) {
66976696
var arg = path.node.argument;
6698-
if (isCCallExpression(arg) || isSSRNodeCallExpression(arg) || isHCallExpression(arg)) {
6697+
if (isCCallExpression(arg) || isSSRNodeCallExpression(arg)) {
66996698
vNodeAst = arg;
67006699
}
67016700
path.stop();
@@ -6752,22 +6751,28 @@ function isCCallExpression(node) {
67526751
}
67536752

67546753
/**
6755-
* check if a call expression has name 'h'
6754+
* check if a call expression has name '_l'
67566755
* match code example:
6757-
* h(__WEBPACK_IMPORTED_MODULE_1__App_vue__["a"])
6756+
* _vm._l()
67586757
* @param {*} node
67596758
*/
6760-
function isHCallExpression(node) {
6759+
function isLCallExpression(node) {
67616760
if (!types.isCallExpression(node)) {
67626761
return false
67636762
}
67646763
if (!Array.isArray(node.arguments)) {
67656764
return false
67666765
}
6767-
if (!types.isIdentifier(node.callee)) {
6766+
if (!types.isMemberExpression(node.callee)) {
6767+
return false
6768+
}
6769+
if (!types.isIdentifier(node.callee.object)) {
6770+
return false
6771+
}
6772+
if (!types.isIdentifier(node.callee.property)) {
67686773
return false
67696774
}
6770-
if (node.callee.name === 'h') {
6775+
if (node.callee.object.name === '_vm' && node.callee.property.name === '_l') {
67716776
return true
67726777
}
67736778

@@ -22854,7 +22859,6 @@ var lib_2 = lib.parseExpression;
2285422859
var lib_3 = lib.tokTypes;
2285522860

2285622861
/* */
22857-
2285822862
var vm$2 = require('vm');
2285922863

2286022864
var onCompilationError$1 = function (err, vm) {
@@ -23010,6 +23014,7 @@ function calcuConditionalExpression(context, ast) {
2301023014
/**
2301123015
* 设置 VNode 子节点的抽象语法树
2301223016
* 对于条件判断语句,通过 VNode 上下文对其求值
23017+
* 如果子语法树里面有循环语句,则当前语法树和子语法树全部都置为 unMatchedAst
2301323018
* @param {VNode} node VNode 节点
2301423019
* @param {Object} ast 抽象语法树
2301523020
*/
@@ -23019,6 +23024,16 @@ function setVNodeChildrenAst(node, ast, context) {
2301923024

2302023025
var unMatchedAst = !astChildren || astChildren.elements.length !== nodeChildren.length;
2302123026

23027+
// 如果子语法树里面有循环语句,则当前语法树和子语法树全部都置为 unMatchedAst
23028+
if (astChildren && Array.isArray(astChildren.elements)) {
23029+
astChildren.elements.forEach(function (node) {
23030+
if (isLCallExpression(node)) {
23031+
ast.unMatchedAst = true;
23032+
unMatchedAst = true;
23033+
}
23034+
});
23035+
}
23036+
2302223037
if (unMatchedAst === false) {
2302323038
node.children.forEach(function (v, i) {
2302423039
var ast = astChildren.elements[i];
@@ -23395,8 +23410,13 @@ function createPatchFunction (ref) {
2339523410
var staticVNode = staticComponent._render();
2339623411
var dynamicVNode = dynamiComponent._render();
2339723412

23398-
// todo 这里的 ast 生成是否可以更统一更严格:仅模板语法生成 ast,否则仅检测当前组件是否全静态
23399-
staticVNode.ast = getVNodeRenderAst(staticAst);
23413+
var childAst = getVNodeRenderAst(staticAst);
23414+
if (childAst) {
23415+
staticVNode.ast = childAst;
23416+
} else {
23417+
staticVNode.ast = Object.assign(staticAst, { unMatchedAst: true });
23418+
}
23419+
2340023420

2340123421
patchContext.patchStates.push({
2340223422
type: 'Component',
@@ -23522,6 +23542,7 @@ function createBundleRendererCreator (
2352223542
var ssrRenderTree = ssrRenderMap[ssrRenderUrl] && ssrRenderMap[ssrRenderUrl].tree;
2352323543

2352423544
if (!ssrRenderTree) {
23545+
console.log('start parse ssr render');
2352523546
return new Promise(function (resolve) {
2352623547
Promise.all([base(context), runner(context)]).then(function (res) {
2352723548
var ssrRender = {};
@@ -23546,6 +23567,9 @@ function createBundleRendererCreator (
2354623567
if (e && e.success) {
2354723568
context.ssrRenderTree = e.ssrRenderTree;
2354823569
ssrRender.tree = e.ssrRenderTree;
23570+
{
23571+
console.log('new ssrRenderTree: ', e.ssrRenderTree);
23572+
}
2354923573
resolve(res[1]);
2355023574
} else {
2355123575
rewriteErrorTrace(e, maps);

0 commit comments

Comments
 (0)