From 6cd07524b6c2cf901905ab1917e03c2bbca49c92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=89=A7=E6=AF=85?= Date: Thu, 13 Aug 2020 11:22:09 +0800 Subject: [PATCH] =?UTF-8?q?test:=20=F0=9F=92=8D=20=E5=AE=8C=E5=96=84=20Rax?= =?UTF-8?q?=20=E5=87=BA=E7=A0=81=E7=9A=84=E7=A4=BA=E4=BE=8B,=20=E8=A7=A3?= =?UTF-8?q?=E5=86=B3=20methods=20=E7=9A=84=E4=B8=8A=E4=B8=8B=E6=96=87?= =?UTF-8?q?=E7=BB=91=E5=AE=9A=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/plugins/component/rax/commonDeps.ts | 6 ++- .../component/rax/containerInjectContext.ts | 1 + .../rax/containerInjectDataSourceEngine.ts | 4 +- .../plugins/component/rax/containerMethods.ts | 13 ++++- .../demo-project/src/pages/Home/index.jsx | 20 +++++-- .../demo2/expected/demo-project/package.json | 3 +- .../demo-project/src/pages/Home/index.jsx | 42 ++++++++++++--- .../demo2/expected/demo-project/src/utils.js | 11 ++++ .../test-cases/rax-app/demo2/schema.json5 | 54 ++++++++++++++++++- 9 files changed, 139 insertions(+), 15 deletions(-) diff --git a/packages/code-generator/src/plugins/component/rax/commonDeps.ts b/packages/code-generator/src/plugins/component/rax/commonDeps.ts index 561bb0022..9e8ad1f57 100644 --- a/packages/code-generator/src/plugins/component/rax/commonDeps.ts +++ b/packages/code-generator/src/plugins/component/rax/commonDeps.ts @@ -19,7 +19,11 @@ const pluginFactory: BuilderComponentPluginFactory = () => { type: ChunkType.STRING, fileType: FileType.JSX, name: COMMON_CHUNK_NAME.ExternalDepsImport, - content: `import { createElement, Component } from 'rax';`, + content: ` + // 注意: 出码引擎注入的临时变量默认都以 "__$$" 开头,禁止在搭建的代码中直接访问。 + // 例外:rax 框架的导出名和各种组件名除外。 + import { createElement, Component } from 'rax'; + `, linkAfter: [], }); diff --git a/packages/code-generator/src/plugins/component/rax/containerInjectContext.ts b/packages/code-generator/src/plugins/component/rax/containerInjectContext.ts index f5bfe65cc..659ccf933 100644 --- a/packages/code-generator/src/plugins/component/rax/containerInjectContext.ts +++ b/packages/code-generator/src/plugins/component/rax/containerInjectContext.ts @@ -67,6 +67,7 @@ const pluginFactory: BuilderComponentPluginFactory = (config?) => get props() { return self.props; }, + ...this._methods, }; return context; diff --git a/packages/code-generator/src/plugins/component/rax/containerInjectDataSourceEngine.ts b/packages/code-generator/src/plugins/component/rax/containerInjectDataSourceEngine.ts index 019383755..686cf5bf4 100644 --- a/packages/code-generator/src/plugins/component/rax/containerInjectDataSourceEngine.ts +++ b/packages/code-generator/src/plugins/component/rax/containerInjectDataSourceEngine.ts @@ -32,7 +32,7 @@ const pluginFactory: BuilderComponentPluginFactory = (config?) => fileType: FileType.JSX, name: COMMON_CHUNK_NAME.ExternalDepsImport, content: ` - import { createDataSourceEngine } from '@ali/lowcode-datasource-engine'; + import { create as __$$createDataSourceEngine } from '@ali/lowcode-datasource-engine'; `, linkAfter: [], }); @@ -43,7 +43,7 @@ const pluginFactory: BuilderComponentPluginFactory = (config?) => name: CLASS_DEFINE_CHUNK_NAME.InsVar, content: ` _dataSourceList = this._defineDataSourceList(); - _dataSourceEngine = createDataSourceEngine(this._dataSourceList, this._context);`, + _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceList, this._context);`, linkAfter: [CLASS_DEFINE_CHUNK_NAME.Start], }); diff --git a/packages/code-generator/src/plugins/component/rax/containerMethods.ts b/packages/code-generator/src/plugins/component/rax/containerMethods.ts index b13c81071..50b3b16a3 100644 --- a/packages/code-generator/src/plugins/component/rax/containerMethods.ts +++ b/packages/code-generator/src/plugins/component/rax/containerMethods.ts @@ -44,7 +44,7 @@ const pluginFactory: BuilderComponentPluginFactory = (config?) => name: RAX_CHUNK_NAME.MethodsBegin, content: ` _defineMethods() { - return ({ + const __$$methods = ({ `, linkAfter: [RAX_CHUNK_NAME.ClassRenderEnd, CLASS_DEFINE_CHUNK_NAME.InsPrivateMethod], }); @@ -55,6 +55,17 @@ const pluginFactory: BuilderComponentPluginFactory = (config?) => name: RAX_CHUNK_NAME.MethodsEnd, content: ` }); + + // 为所有的方法绑定上下文 + Object.entries(__$$methods).forEach(([methodName, method]) => { + if (typeof method === 'function') { + __$$methods[methodName] = (...args) => { + return method.apply(this._context, args); + } + } + }); + + return __$$methods; } `, linkAfter: [RAX_CHUNK_NAME.MethodsBegin, RAX_CHUNK_NAME.MethodsContent], diff --git a/packages/code-generator/test-cases/rax-app/demo1/expected/demo-project/src/pages/Home/index.jsx b/packages/code-generator/test-cases/rax-app/demo1/expected/demo-project/src/pages/Home/index.jsx index 1ae8e9192..89960d6ef 100644 --- a/packages/code-generator/test-cases/rax-app/demo1/expected/demo-project/src/pages/Home/index.jsx +++ b/packages/code-generator/test-cases/rax-app/demo1/expected/demo-project/src/pages/Home/index.jsx @@ -1,10 +1,12 @@ +// 注意: 出码引擎注入的临时变量默认都以 "__$$" 开头,禁止在搭建的代码中直接访问。 +// 例外:rax 框架的导出名和各种组件名除外。 import { createElement, Component } from 'rax'; import Page from 'rax-view'; import Text from 'rax-text'; -import { createDataSourceEngine } from '@ali/lowcode-datasource-engine'; +import { create as __$$createDataSourceEngine } from '@ali/lowcode-datasource-engine'; import __$$projectUtils from '../../utils'; @@ -16,7 +18,7 @@ class Home$$Page extends Component { _context = this._createContext(); _dataSourceList = this._defineDataSourceList(); - _dataSourceEngine = createDataSourceEngine(this._dataSourceList, this._context); + _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceList, this._context); _utils = this._defineUtils(); @@ -62,6 +64,7 @@ class Home$$Page extends Component { get props() { return self.props; }, + ...this._methods, }; return context; @@ -86,7 +89,18 @@ class Home$$Page extends Component { } _defineMethods() { - return {}; + const __$$methods = {}; + + // 为所有的方法绑定上下文 + Object.entries(__$$methods).forEach(([methodName, method]) => { + if (typeof method === 'function') { + __$$methods[methodName] = (...args) => { + return method.apply(this._context, args); + }; + } + }); + + return __$$methods; } } diff --git a/packages/code-generator/test-cases/rax-app/demo2/expected/demo-project/package.json b/packages/code-generator/test-cases/rax-app/demo2/expected/demo-project/package.json index 8aad3e1ad..f14719b11 100644 --- a/packages/code-generator/test-cases/rax-app/demo2/expected/demo-project/package.json +++ b/packages/code-generator/test-cases/rax-app/demo2/expected/demo-project/package.json @@ -17,7 +17,8 @@ "rax-text": "^1.0.0", "rax-image": "^1.0.0", "moment": "*", - "lodash": "*" + "lodash": "*", + "universal-toast": "^1.2.0" }, "devDependencies": { "build-plugin-rax-app": "^5.0.0", diff --git a/packages/code-generator/test-cases/rax-app/demo2/expected/demo-project/src/pages/Home/index.jsx b/packages/code-generator/test-cases/rax-app/demo2/expected/demo-project/src/pages/Home/index.jsx index 1f1e8cfea..1cad2aa0c 100644 --- a/packages/code-generator/test-cases/rax-app/demo2/expected/demo-project/src/pages/Home/index.jsx +++ b/packages/code-generator/test-cases/rax-app/demo2/expected/demo-project/src/pages/Home/index.jsx @@ -1,3 +1,5 @@ +// 注意: 出码引擎注入的临时变量默认都以 "__$$" 开头,禁止在搭建的代码中直接访问。 +// 例外:rax 框架的导出名和各种组件名除外。 import { createElement, Component } from 'rax'; import View from 'rax-view'; @@ -6,7 +8,7 @@ import Text from 'rax-text'; import Image from 'rax-image'; -import { createDataSourceEngine } from '@ali/lowcode-datasource-engine'; +import { create as __$$createDataSourceEngine } from '@ali/lowcode-datasource-engine'; import __$$projectUtils from '../../utils'; @@ -30,9 +32,11 @@ class Home$$Page extends Component { }; _methods = this._defineMethods(); + _context = this._createContext(); + _dataSourceList = this._defineDataSourceList(); - _dataSourceEngine = createDataSourceEngine(this._dataSourceList, this._context); + _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceList, this._context); _utils = this._defineUtils(); @@ -57,7 +61,7 @@ class Home$$Page extends Component { source={{ uri: __$$eval(() => __$$context.state.user.avatar) }} style={{ width: '32px', height: '32px' }} /> - + __$$context.hello)}> {__$$eval(() => __$$context.state.user.name)} {__$$eval(() => __$$context.state.user.age)}岁 @@ -67,7 +71,15 @@ class Home$$Page extends Component { === Orders: === {__$$evalArray(() => __$$context.state.orders).map((item, index) => ( - + + function () { + __$$context.utils.recordEvent(`CLICK_ORDER`, item.title); + }, + )} + > item.coverUrl) }} style={{ width: '80px', height: '60px' }} /> @@ -77,6 +89,11 @@ class Home$$Page extends Component { ))} + + 操作提示: + 1. 点击会员名,可以弹出 Toast "Hello xxx!" + 2. 点击订单,会记录点击的订单信息,并弹出 Toast 提示 + ); } @@ -109,6 +126,7 @@ class Home$$Page extends Component { get props() { return self.props; }, + ...this._methods, }; return context; @@ -141,11 +159,23 @@ class Home$$Page extends Component { } _defineMethods() { - return { + const __$$methods = { hello: function hello() { - console.log('Hello world!'); + this.utils.Toast.show(`Hello ${this.state.user.name}!`); + console.log(`Hello ${this.state.user.name}!`); }, }; + + // 为所有的方法绑定上下文 + Object.entries(__$$methods).forEach(([methodName, method]) => { + if (typeof method === 'function') { + __$$methods[methodName] = (...args) => { + return method.apply(this._context, args); + }; + } + }); + + return __$$methods; } } diff --git a/packages/code-generator/test-cases/rax-app/demo2/expected/demo-project/src/utils.js b/packages/code-generator/test-cases/rax-app/demo2/expected/demo-project/src/utils.js index 6fb1f681b..a9612b3d2 100644 --- a/packages/code-generator/test-cases/rax-app/demo2/expected/demo-project/src/utils.js +++ b/packages/code-generator/test-cases/rax-app/demo2/expected/demo-project/src/utils.js @@ -2,14 +2,25 @@ import moment from 'moment'; import clone from 'lodash/clone'; +import Toast from 'universal-toast'; + const formatPrice = function formatPrice(price, unit) { return Number(price).toFixed(2) + unit; }; +const recordEvent = function recordEvent(eventName, eventDetail) { + this.utils.Toast.show(`[EVENT]: ${eventName} ${eventDetail}`); + console.log(`[EVENT]: ${eventName} (detail: %o) (user: %o)`, eventDetail, this.state.user); +}; + export default { formatPrice, + recordEvent, + moment, clone, + + Toast, }; diff --git a/packages/code-generator/test-cases/rax-app/demo2/schema.json5 b/packages/code-generator/test-cases/rax-app/demo2/schema.json5 index 161d7fe50..d735dafde 100644 --- a/packages/code-generator/test-cases/rax-app/demo2/schema.json5 +++ b/packages/code-generator/test-cases/rax-app/demo2/schema.json5 @@ -55,7 +55,7 @@ methods: { hello: { type: 'JSExpression', - value: 'function hello(){ console.log("Hello world!"); }', + value: 'function hello(){\n this.utils.Toast.show(`Hello ${this.state.user.name}!`);\n console.log(`Hello ${this.state.user.name}!`); }', }, }, dataSource: { @@ -132,6 +132,12 @@ }, { componentName: 'View', + props: { + onClick: { + type: 'JSFunction', + value: 'this.hello', + }, + }, children: [ { componentName: 'Text', @@ -172,6 +178,10 @@ }, props: { style: { flexDirection: 'row' }, + onClick: { + type: 'JSFunction', + value: 'function(){ this.utils.recordEvent(`CLICK_ORDER`, this.item.title) }', + }, }, children: [ { @@ -215,10 +225,31 @@ }, ], }, + { + componentName: 'View', + children: [ + { + componentName: 'Text', + props: {}, + children: '操作提示:', + }, + { + componentName: 'Text', + props: {}, + children: '1. 点击会员名,可以弹出 Toast "Hello xxx!"', + }, + { + componentName: 'Text', + props: {}, + children: '2. 点击订单,会记录点击的订单信息,并弹出 Toast 提示', + }, + ], + }, ], }, ], utils: [ + // 可以直接定义一个函数 { name: 'formatPrice', type: 'function', @@ -227,6 +258,16 @@ value: 'function formatPrice(price, unit) { return Number(price).toFixed(2) + unit; }', }, }, + // 在 utils 里面也可以用 this 访问当前上下文: + { + name: 'recordEvent', + type: 'function', + content: { + type: 'JSFunction', + value: 'function recordEvent(eventName, eventDetail) { \n this.utils.Toast.show(`[EVENT]: ${eventName} ${eventDetail}`);\n console.log(`[EVENT]: ${eventName} (detail: %o) (user: %o)`, eventDetail, this.state.user); }', + }, + }, + // 也可以直接从 npm 包引入 (下例等价于 `import moment from 'moment';`) { name: 'moment', type: 'npm', @@ -236,6 +277,7 @@ exportName: 'moment', }, }, + // 可以引入子目录(下例等价于 `import clone from 'lodash/clone';`) { name: 'clone', type: 'npm', @@ -247,6 +289,16 @@ main: '/clone', }, }, + // 支持 TNPM + { + name: 'Toast', + type: 'tnpm', + content: { + package: 'universal-toast', + version: '^1.2.0', + exportName: 'Toast', // TODO: 这个 exportName 是否可以省略?省略后默认是上一层的 name? + }, + }, ], config: { sdkVersion: '1.0.3',