Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
DCloud
uni-app
提交
c83c6ceb
U
uni-app
项目概览
DCloud
/
uni-app
6 个月 前同步成功
通知
751
Star
38709
Fork
3642
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
8
列表
看板
标记
里程碑
合并请求
1
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
U
uni-app
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
8
Issue
8
列表
看板
标记
里程碑
合并请求
1
合并请求
1
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
c83c6ceb
编写于
10月 15, 2021
作者:
fxy060608
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
wip(mp): transform static import to dynamic import
上级
236ad155
变更
22
显示空白变更内容
内联
并排
Showing
22 changed file
with
618 addition
and
113 deletion
+618
-113
packages/uni-app-plus/dist/uni-app-service.es.js
packages/uni-app-plus/dist/uni-app-service.es.js
+54
-15
packages/uni-cli-shared/package.json
packages/uni-cli-shared/package.json
+1
-0
packages/uni-cli-shared/src/checkUpdate.ts
packages/uni-cli-shared/src/checkUpdate.ts
+1
-1
packages/uni-cli-shared/src/easycom.ts
packages/uni-cli-shared/src/easycom.ts
+1
-1
packages/uni-cli-shared/src/mp/imports.ts
packages/uni-cli-shared/src/mp/imports.ts
+48
-0
packages/uni-cli-shared/src/mp/index.ts
packages/uni-cli-shared/src/mp/index.ts
+1
-0
packages/uni-h5/dist/uni-h5.es.js
packages/uni-h5/dist/uni-h5.es.js
+2
-2
packages/uni-mp-compiler/__tests__/transformElement.spec.ts
packages/uni-mp-compiler/__tests__/transformElement.spec.ts
+227
-0
packages/uni-mp-compiler/__tests__/vFor.spec.ts
packages/uni-mp-compiler/__tests__/vFor.spec.ts
+4
-1
packages/uni-mp-compiler/__tests__/vIf.spec.ts
packages/uni-mp-compiler/__tests__/vIf.spec.ts
+7
-7
packages/uni-mp-compiler/src/codegen.ts
packages/uni-mp-compiler/src/codegen.ts
+53
-8
packages/uni-mp-compiler/src/compile.ts
packages/uni-mp-compiler/src/compile.ts
+10
-1
packages/uni-mp-compiler/src/errors.ts
packages/uni-mp-compiler/src/errors.ts
+7
-0
packages/uni-mp-compiler/src/options.ts
packages/uni-mp-compiler/src/options.ts
+11
-2
packages/uni-mp-compiler/src/transform.ts
packages/uni-mp-compiler/src/transform.ts
+10
-0
packages/uni-mp-compiler/src/transforms/transformElement.ts
packages/uni-mp-compiler/src/transforms/transformElement.ts
+131
-72
packages/uni-mp-vite/__tests__/test.js
packages/uni-mp-vite/__tests__/test.js
+2
-0
packages/uni-mp-vite/package.json
packages/uni-mp-vite/package.json
+3
-0
packages/uni-mp-vite/src/index.ts
packages/uni-mp-vite/src/index.ts
+2
-0
packages/uni-mp-vite/src/plugins/component.ts
packages/uni-mp-vite/src/plugins/component.ts
+40
-0
packages/uni-vue/src/componentOptions/hooks.ts
packages/uni-vue/src/componentOptions/hooks.ts
+2
-2
yarn.lock
yarn.lock
+1
-1
未找到文件。
packages/uni-app-plus/dist/uni-app-service.es.js
浏览文件 @
c83c6ceb
...
...
@@ -5681,6 +5681,7 @@ var serviceContext = (function (vue) {
};
const API_CLOSE_AUTH_VIEW = 'closeAuthView';
const API_GET_CHECK_BOX_STATE = 'getCheckBoxState';
const API_GET_UNIVERIFY_MANAGER = 'getUniverifyManager';
const API_SHREA = 'share';
const SCENE = [
...
...
@@ -6386,7 +6387,7 @@ var serviceContext = (function (vue) {
let deviceId;
function deviceId$1 () {
deviceId = deviceId || plus.
runtime.getDCloudId()
;
deviceId = deviceId || plus.
device.uuid
;
return deviceId;
}
...
...
@@ -8985,7 +8986,7 @@ var serviceContext = (function (vue) {
errMsg: 'getLocation:ok',
});
}
const getLocation = defineAsyncApi(API_GET_LOCATION, ({ type = 'wgs84', geocode = false, altitude = false }, { resolve, reject }) => {
const getLocation = defineAsyncApi(API_GET_LOCATION, ({ type = 'wgs84', geocode = false, altitude = false
, highAccuracyExpireTime,
}, { resolve, reject }) => {
plus.geolocation.getCurrentPosition((position) => {
getLocationSuccess(type, position, resolve);
}, (e) => {
...
...
@@ -8998,6 +8999,7 @@ var serviceContext = (function (vue) {
}, {
geocode: geocode,
enableHighAccuracy: altitude,
timeout: highAccuracyExpireTime,
});
}, GetLocationProtocol, GetLocationOptions);
...
...
@@ -9545,6 +9547,7 @@ var serviceContext = (function (vue) {
}
}, GetProviderProtocol);
let univerifyManager;
function getService(provider) {
return new Promise((resolve, reject) => {
plus.oauth.getServices((services) => {
...
...
@@ -9692,24 +9695,59 @@ var serviceContext = (function (vue) {
*/
function univerifyButtonsClickHandling(univerifyStyle, errorCallback) {
if (isPlainObject(univerifyStyle) &&
univerifyStyle.buttons &&
toTypeString(univerifyStyle.buttons.list) === '[object Array]' &&
univerifyStyle.buttons.list.length > 0) {
isPlainObject(univerifyStyle.buttons) &&
toTypeString(univerifyStyle.buttons.list) === '[object Array]') {
univerifyStyle.buttons.list.forEach((button, index) => {
univerifyStyle.buttons.list[index].onclick = function () {
_closeAuthView().then(() => {
errorCallback({
const res = {
code: '30008',
message: '用户点击了自定义按钮',
index,
provider: button.provider,
});
};
isPlainObject(univerifyManager)
? univerifyManager._triggerUniverifyButtonsClick(res)
: _closeAuthView().then(() => {
errorCallback(res);
});
};
});
}
return univerifyStyle;
}
class UniverifyManager {
constructor() {
this.provider = 'univerify';
this.eventName = 'api.univerifyButtonsClick';
}
close() {
closeAuthView();
}
login(options) {
login(this._getOptions(options));
}
getCheckBoxState(options) {
getCheckBoxState(options);
}
preLogin(options) {
preLogin(this._getOptions(options));
}
onButtonsClick(callback) {
UniServiceJSBridge.on(this.eventName, callback);
}
offButtonsClick(callback) {
UniServiceJSBridge.off(this.eventName, callback);
}
_triggerUniverifyButtonsClick(res) {
UniServiceJSBridge.emit(this.eventName, res);
}
_getOptions(options = {}) {
return extend({}, options, { provider: this.provider });
}
}
const getUniverifyManager = defineSyncApi(API_GET_UNIVERIFY_MANAGER, () => {
return univerifyManager || (univerifyManager = new UniverifyManager());
});
const registerRuntime = defineSyncApi('registerRuntime', (runtime) => {
// @ts-expect-error
...
...
@@ -9859,7 +9897,7 @@ var serviceContext = (function (vue) {
});
}
catch (e) {
console.error(e.message +
'\n'
+ e.stack);
console.error(e.message +
LINEFEED
+ e.stack);
}
}
}
...
...
@@ -12771,6 +12809,7 @@ var serviceContext = (function (vue) {
preLogin: preLogin,
closeAuthView: closeAuthView,
getCheckBoxState: getCheckBoxState,
getUniverifyManager: getUniverifyManager,
registerRuntime: registerRuntime,
share: share,
shareWithSystem: shareWithSystem,
...
...
packages/uni-cli-shared/package.json
浏览文件 @
c83c6ceb
...
...
@@ -23,6 +23,7 @@
"chokidar"
:
"^3.5.2"
,
"compare-versions"
:
"^3.6.0"
,
"debug"
:
"^4.3.1"
,
"es-module-lexer"
:
"^0.9.3"
,
"estree-walker"
:
"^2.0.2"
,
"fast-glob"
:
"^3.2.7"
,
"fs-extra"
:
"^10.0.0"
,
...
...
packages/uni-cli-shared/src/checkUpdate.ts
浏览文件 @
c83c6ceb
...
...
@@ -188,7 +188,7 @@ function writeCheckUpdateCache(
debugCheckUpdate
(
'
write:
'
,
filepath
,
updateCache
)
try
{
fs
.
outputFileSync
(
filepath
,
JSON
.
stringify
(
updateCache
))
}
catch
(
e
:
any
)
{
}
catch
(
e
)
{
debugCheckUpdate
(
'
write.error
'
,
e
)
}
}
...
...
packages/uni-cli-shared/src/easycom.ts
浏览文件 @
c83c6ceb
...
...
@@ -24,7 +24,7 @@ interface EasycomCustom {
[
key
:
string
]:
string
}
const
debugEasycom
=
debug
(
'
uni:easycom
'
)
const
debugEasycom
=
debug
(
'
vite:
uni:easycom
'
)
const
easycoms
:
EasycomMatcher
[]
=
[]
...
...
packages/uni-cli-shared/src/mp/imports.ts
0 → 100644
浏览文件 @
c83c6ceb
import
path
from
'
path
'
import
{
PluginContext
}
from
'
rollup
'
import
{
init
,
parse
as
parseImports
,
ImportSpecifier
}
from
'
es-module-lexer
'
import
{
extend
}
from
'
@vue/shared
'
import
{
EXTNAME_VUE
,
EXTNAME_VUE_RE
}
from
'
../constants
'
export
async
function
findVueComponentImports
(
source
:
string
,
importer
:
string
,
resolve
:
PluginContext
[
'
resolve
'
]
)
{
await
init
let
imports
:
readonly
ImportSpecifier
[]
=
[]
// strip UTF-8 BOM
if
(
source
.
charCodeAt
(
0
)
===
0xfeff
)
{
source
=
source
.
slice
(
1
)
}
try
{
imports
=
parseImports
(
source
)[
0
]
}
catch
(
e
:
any
)
{
console
.
error
(
e
)
}
if
(
!
imports
.
length
)
{
return
[]
}
const
rewriteImports
:
ImportSpecifier
[]
=
[]
for
(
let
i
=
0
;
i
<
imports
.
length
;
i
++
)
{
const
importSpecifier
=
imports
[
i
]
const
{
n
}
=
importSpecifier
if
(
!
n
)
{
continue
}
const
extname
=
path
.
extname
(
n
)
// 仅处理没有后缀,或后缀是.vue,.nvue的文件
if
(
extname
&&
!
EXTNAME_VUE
.
includes
(
extname
))
{
continue
}
const
res
=
await
resolve
(
n
,
importer
)
if
(
!
res
)
{
continue
}
if
(
EXTNAME_VUE_RE
.
test
(
res
.
id
))
{
rewriteImports
.
push
(
extend
(
importSpecifier
,
{
n
:
res
.
id
}))
}
}
return
rewriteImports
}
packages/uni-cli-shared/src/mp/index.ts
浏览文件 @
c83c6ceb
export
*
from
'
./event
'
export
{
findVueComponentImports
}
from
'
./imports
'
packages/uni-h5/dist/uni-h5.es.js
浏览文件 @
c83c6ceb
...
...
@@ -17198,13 +17198,13 @@ function getJSONP(url, options, success, error) {
js.src = url + (url.indexOf("?") >= 0 ? "&" : "?") + callbackKey + "=" + callbackName;
document.body.appendChild(js);
}
const getLocation = /* @__PURE__ */ defineAsyncApi(API_GET_LOCATION, ({ type, altitude }, { resolve, reject }) => {
const getLocation = /* @__PURE__ */ defineAsyncApi(API_GET_LOCATION, ({ type, altitude
, highAccuracyExpireTime
}, { resolve, reject }) => {
const mapInfo = getMapInfo();
new Promise((resolve2, reject2) => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition((res) => resolve2(res.coords), reject2, {
enableHighAccuracy: altitude,
timeout: 1e3 * 100
timeout:
highAccuracyExpireTime ||
1e3 * 100
});
} else {
reject2(new Error("device nonsupport geolocation"));
...
...
packages/uni-mp-compiler/__tests__/transformElement.spec.ts
0 → 100644
浏览文件 @
c83c6ceb
import
{
BindingTypes
,
ElementNode
,
RootNode
}
from
'
@vue/compiler-core
'
import
{
compile
}
from
'
../src
'
import
{
MPErrorCodes
}
from
'
../src/errors
'
import
{
CodegenRootNode
,
CompilerOptions
}
from
'
../src/options
'
import
{
BindingComponentTypes
}
from
'
../src/transform
'
function
parseWithElementTransform
(
template
:
string
,
options
:
CompilerOptions
=
{}
):
{
code
:
string
preamble
:
string
root
:
RootNode
node
:
ElementNode
}
{
const
{
ast
,
code
,
preamble
}
=
compile
(
`<div>
${
template
}
</div>`
,
options
)
const
node
=
(
ast
as
any
).
children
[
0
].
children
[
0
]
return
{
code
,
preamble
,
root
:
ast
,
node
,
}
}
describe
(
'
compiler: element transform
'
,
()
=>
{
test
(
'
import + resolve component
'
,
()
=>
{
const
{
root
,
code
}
=
parseWithElementTransform
(
`<Foo/>`
)
expect
((
root
as
CodegenRootNode
).
bindingComponents
).
toEqual
({
Foo
:
{
name
:
'
_component_Foo
'
,
type
:
BindingComponentTypes
.
UNKNOWN
},
})
expect
(
code
).
toContain
(
`if (!Math) {Math.max.call(Max, _component_Foo)}`
)
})
test
(
'
import + resolve component multi
'
,
()
=>
{
const
{
root
,
code
}
=
parseWithElementTransform
(
`<Foo/><Bar/><Example/><Test/>`
,
{
filename
:
`/foo/bar/Test.vue?vue&type=template`
,
bindingMetadata
:
{
Example
:
BindingTypes
.
SETUP_MAYBE_REF
,
},
}
)
expect
((
root
as
CodegenRootNode
).
bindingComponents
).
toEqual
({
Foo
:
{
name
:
'
_component_Foo
'
,
type
:
BindingComponentTypes
.
UNKNOWN
},
Bar
:
{
name
:
'
_component_Bar
'
,
type
:
BindingComponentTypes
.
UNKNOWN
},
Example
:
{
name
:
'
$setup["Example"]
'
,
type
:
BindingComponentTypes
.
SETUP
},
Test
:
{
name
:
'
_component_Test
'
,
type
:
BindingComponentTypes
.
SELF
},
})
expect
(
code
).
toContain
(
`if (!Math) {Math.max.call(Max, _component_Foo, _component_Bar, $setup["Example"], _component_Test)}`
)
})
test
(
'
resolve implcitly self-referencing component
'
,
()
=>
{
const
{
root
,
code
}
=
parseWithElementTransform
(
`<Example/>`
,
{
filename
:
`/foo/bar/Example.vue?vue&type=template`
,
})
expect
((
root
as
CodegenRootNode
).
bindingComponents
).
toEqual
({
Example
:
{
name
:
'
_component_Example
'
,
type
:
BindingComponentTypes
.
SELF
},
})
expect
(
code
).
toContain
(
`if (!Math) {Math.max.call(Max, _component_Example)}`
)
})
test
(
'
resolve component from setup bindings
'
,
()
=>
{
const
{
root
,
code
}
=
parseWithElementTransform
(
`<Example/>`
,
{
bindingMetadata
:
{
Example
:
BindingTypes
.
SETUP_MAYBE_REF
,
},
})
expect
((
root
as
CodegenRootNode
).
bindingComponents
).
toEqual
({
Example
:
{
name
:
'
$setup["Example"]
'
,
type
:
BindingComponentTypes
.
SETUP
},
})
expect
(
code
).
toContain
(
`if (!Math) {Math.max.call(Max, $setup["Example"])}`
)
})
test
(
'
resolve component from setup bindings (inline)
'
,
()
=>
{
const
{
root
,
preamble
}
=
parseWithElementTransform
(
`<Example/>`
,
{
inline
:
true
,
bindingMetadata
:
{
Example
:
BindingTypes
.
SETUP_MAYBE_REF
,
},
})
expect
((
root
as
CodegenRootNode
).
bindingComponents
).
toEqual
({
Example
:
{
name
:
'
_unref(Example)
'
,
type
:
BindingComponentTypes
.
SETUP
},
})
expect
(
preamble
).
toContain
(
`if (!Math) {Math.max.call(Max, _unref(Example))}`
)
})
test
(
'
resolve component from setup bindings (inline const)
'
,
()
=>
{
const
{
root
,
preamble
}
=
parseWithElementTransform
(
`<Example/>`
,
{
inline
:
true
,
bindingMetadata
:
{
Example
:
BindingTypes
.
SETUP_CONST
,
},
})
expect
((
root
as
CodegenRootNode
).
bindingComponents
).
toEqual
({
Example
:
{
name
:
'
Example
'
,
type
:
BindingComponentTypes
.
SETUP
},
})
expect
(
preamble
).
toContain
(
`if (!Math) {Math.max.call(Max, Example)}`
)
})
test
(
'
resolve namespaced component from setup bindings
'
,
()
=>
{
const
onError
=
jest
.
fn
()
parseWithElementTransform
(
`<Foo.Example/>`
,
{
onError
,
bindingMetadata
:
{
Foo
:
BindingTypes
.
SETUP_MAYBE_REF
,
},
})
expect
(
onError
).
toHaveBeenCalledTimes
(
1
)
expect
(
onError
).
toHaveBeenCalledWith
(
expect
.
objectContaining
({
code
:
MPErrorCodes
.
X_NOT_SUPPORTED
,
})
)
})
test
(
'
resolve namespaced component from setup bindings (inline)
'
,
()
=>
{
const
onError
=
jest
.
fn
()
parseWithElementTransform
(
`<Foo.Example/>`
,
{
onError
,
inline
:
true
,
bindingMetadata
:
{
Foo
:
BindingTypes
.
SETUP_MAYBE_REF
,
},
})
expect
(
onError
).
toHaveBeenCalledTimes
(
1
)
expect
(
onError
).
toHaveBeenCalledWith
(
expect
.
objectContaining
({
code
:
MPErrorCodes
.
X_NOT_SUPPORTED
,
})
)
})
test
(
'
resolve namespaced component from setup bindings (inline const)
'
,
()
=>
{
const
onError
=
jest
.
fn
()
parseWithElementTransform
(
`<Foo.Example/>`
,
{
onError
,
inline
:
true
,
bindingMetadata
:
{
Foo
:
BindingTypes
.
SETUP_CONST
,
},
})
expect
(
onError
).
toHaveBeenCalledTimes
(
1
)
expect
(
onError
).
toHaveBeenCalledWith
(
expect
.
objectContaining
({
code
:
MPErrorCodes
.
X_NOT_SUPPORTED
,
})
)
})
test
(
'
do not resolve component from non-script-setup bindings
'
,
()
=>
{
const
bindingMetadata
=
{
Example
:
BindingTypes
.
SETUP_MAYBE_REF
,
}
Object
.
defineProperty
(
bindingMetadata
,
'
__isScriptSetup
'
,
{
value
:
false
})
const
{
root
}
=
parseWithElementTransform
(
`<Example/>`
,
{
bindingMetadata
,
})
expect
((
root
as
CodegenRootNode
).
bindingComponents
).
toEqual
({
Example
:
{
name
:
'
_component_Example
'
,
type
:
BindingComponentTypes
.
UNKNOWN
,
},
})
})
describe
(
'
dynamic component
'
,
()
=>
{
test
(
'
static binding
'
,
()
=>
{
const
onError
=
jest
.
fn
()
parseWithElementTransform
(
`<component is="foo" />`
,
{
onError
,
})
expect
(
onError
).
toHaveBeenCalledTimes
(
1
)
expect
(
onError
).
toHaveBeenCalledWith
(
expect
.
objectContaining
({
code
:
MPErrorCodes
.
X_DYNAMIC_COMPONENT_NOT_SUPPORTED
,
})
)
})
test
(
'
capitalized version w/ static binding
'
,
()
=>
{
const
onError
=
jest
.
fn
()
parseWithElementTransform
(
`<Component is="foo" />`
,
{
onError
,
})
expect
(
onError
).
toHaveBeenCalledTimes
(
1
)
expect
(
onError
).
toHaveBeenCalledWith
(
expect
.
objectContaining
({
code
:
MPErrorCodes
.
X_DYNAMIC_COMPONENT_NOT_SUPPORTED
,
})
)
})
test
(
'
dynamic binding
'
,
()
=>
{
const
onError
=
jest
.
fn
()
parseWithElementTransform
(
`<component :is="foo" />`
,
{
onError
,
})
expect
(
onError
).
toHaveBeenCalledTimes
(
1
)
expect
(
onError
).
toHaveBeenCalledWith
(
expect
.
objectContaining
({
code
:
MPErrorCodes
.
X_DYNAMIC_COMPONENT_NOT_SUPPORTED
,
})
)
})
test
(
'
v-is
'
,
()
=>
{
const
onError
=
jest
.
fn
()
parseWithElementTransform
(
`<div v-is="'foo'" />`
,
{
onError
,
})
expect
(
onError
).
toHaveBeenCalledTimes
(
1
)
expect
(
onError
).
toHaveBeenCalledWith
(
expect
.
objectContaining
({
code
:
MPErrorCodes
.
X_V_IS_NOT_SUPPORTED
,
})
)
})
})
})
packages/uni-mp-compiler/__tests__/vFor.spec.ts
浏览文件 @
c83c6ceb
...
...
@@ -481,7 +481,10 @@ describe(`compiler: v-for`, () => {
test
(
'
should prefix v-for source w/ complex expression
'
,
()
=>
{
const
{
node
}
=
parseWithForTransform
(
`<view v-for="i in list.concat([foo])"/>`
,
{
prefixIdentifiers
:
true
,
skipTransformIdentifier
:
true
}
{
prefixIdentifiers
:
true
,
skipTransformIdentifier
:
true
,
}
)
expect
(
node
.
vFor
.
source
).
toMatchObject
({
type
:
NodeTypes
.
COMPOUND_EXPRESSION
,
...
...
packages/uni-mp-compiler/__tests__/vIf.spec.ts
浏览文件 @
c83c6ceb
...
...
@@ -61,13 +61,13 @@ describe(`compiler: v-if`, () => {
)
})
test
(
`component v-if`
,
()
=>
{
assert
(
`<Component v-if="ok"></Component>`
,
`<Component wx:if="{{a}}"></Component>`
,
`(_ctx, _cache) => {
return { a: _ctx.ok, ...(_ctx.ok ? {} : {}) }
}`
)
//
assert(
//
`<Component v-if="ok"></Component>`,
//
`<Component wx:if="{{a}}"></Component>`,
//
`(_ctx, _cache) => {
//
return { a: _ctx.ok, ...(_ctx.ok ? {} : {}) }
//
}`
//
)
})
test
(
`v-if + v-else`
,
()
=>
{
assert
(
...
...
packages/uni-mp-compiler/src/codegen.ts
浏览文件 @
c83c6ceb
...
...
@@ -10,13 +10,17 @@ import {
TextNode
,
TO_DISPLAY_STRING
,
}
from
'
@vue/compiler-core
'
import
{
Expression
}
from
'
@babel/types
'
import
{
default
as
babelGenerate
}
from
'
@babel/generator
'
import
{
CodegenOptions
,
CodegenScope
}
from
'
./options
'
import
{
addImportDeclaration
,
matchEasycom
}
from
'
@dcloudio/uni-cli-shared
'
import
{
CodegenOptions
,
CodegenRootNode
}
from
'
./options
'
import
{
createObjectExpression
}
from
'
./ast
'
import
{
Expression
}
from
'
@babel/types
'
import
{
BindingComponentTypes
,
TransformContext
}
from
'
./transform
'
interface
CodegenContext
extends
CodegenOptions
{
code
:
string
bindingComponents
:
TransformContext
[
'
bindingComponents
'
]
indentLevel
:
number
push
(
code
:
string
,
node
?:
CodegenNode
):
void
indent
():
void
...
...
@@ -25,8 +29,7 @@ interface CodegenContext extends CodegenOptions {
}
export
function
generate
(
ast
:
RootNode
,
scope
:
CodegenScope
,
ast
:
CodegenRootNode
,
options
:
CodegenOptions
):
Omit
<
CodegenResult
,
'
ast
'
>
{
const
context
=
createCodegenContext
(
ast
,
options
)
...
...
@@ -82,7 +85,7 @@ export function generate(
}
push
(
`return `
)
push
(
genBabelExpr
(
createObjectExpression
(
scope
.
properties
)))
push
(
genBabelExpr
(
createObjectExpression
(
ast
.
scope
.
properties
)))
if
(
useWithBlock
)
{
deindent
()
push
(
`}`
)
...
...
@@ -96,7 +99,7 @@ export function generate(
}
function
createCodegenContext
(
ast
:
RootNode
,
ast
:
Codegen
RootNode
,
{
mode
=
'
function
'
,
prefixIdentifiers
=
mode
===
'
module
'
,
...
...
@@ -114,6 +117,7 @@ function createCodegenContext(
scopeId
,
runtimeGlobalName
,
runtimeModuleName
,
bindingComponents
:
ast
.
bindingComponents
,
isTS
,
code
:
``
,
indentLevel
:
0
,
...
...
@@ -142,8 +146,45 @@ function createCodegenContext(
return
context
}
function
genComponentImports
(
bindingComponents
:
TransformContext
[
'
bindingComponents
'
],
{
push
}:
CodegenContext
)
{
const
importDeclarations
:
string
[]
=
[]
Object
.
keys
(
bindingComponents
).
forEach
((
tag
)
=>
{
const
{
name
,
type
}
=
bindingComponents
[
tag
]
if
(
type
===
BindingComponentTypes
.
UNKNOWN
)
{
const
source
=
matchEasycom
(
tag
)
if
(
source
)
{
addImportDeclaration
(
importDeclarations
,
name
,
source
)
}
}
})
importDeclarations
.
forEach
((
str
)
=>
push
(
str
))
}
function
genComponents
(
bindingComponents
:
TransformContext
[
'
bindingComponents
'
],
{
push
}:
CodegenContext
)
{
const
components
=
Object
.
keys
(
bindingComponents
).
map
(
(
tag
)
=>
bindingComponents
[
tag
].
name
)
if
(
components
.
length
)
{
push
(
`if (!Math) {`
)
push
(
`Math.max.call(Max,
${
components
.
map
((
name
)
=>
name
).
join
(
'
,
'
)}
)`
)
push
(
`}`
)
}
}
function
genFunctionPreamble
(
ast
:
RootNode
,
context
:
CodegenContext
)
{
const
{
prefixIdentifiers
,
push
,
newline
,
runtimeGlobalName
}
=
context
const
{
prefixIdentifiers
,
push
,
newline
,
runtimeGlobalName
,
bindingComponents
,
}
=
context
const
VueBinding
=
runtimeGlobalName
const
aliasHelper
=
(
s
:
symbol
)
=>
`
${
helperNameMap
[
s
]}
: _
${
helperNameMap
[
s
]}
`
if
(
ast
.
helpers
.
length
>
0
)
{
...
...
@@ -155,6 +196,8 @@ function genFunctionPreamble(ast: RootNode, context: CodegenContext) {
push
(
`const _Vue =
${
VueBinding
}
\n`
)
}
}
genComponentImports
(
bindingComponents
,
context
)
genComponents
(
bindingComponents
,
context
)
newline
()
push
(
`return `
)
}
...
...
@@ -164,7 +207,7 @@ function genModulePreamble(
context
:
CodegenContext
,
inline
?:
boolean
)
{
const
{
push
,
newline
,
runtimeModuleName
}
=
context
const
{
push
,
newline
,
runtimeModuleName
,
bindingComponents
}
=
context
if
(
ast
.
helpers
.
length
)
{
push
(
`import {
${
ast
.
helpers
...
...
@@ -172,6 +215,8 @@ function genModulePreamble(
.
join
(
'
,
'
)}
} from
${
JSON
.
stringify
(
runtimeModuleName
)}
\n`
)
}
genComponentImports
(
bindingComponents
,
context
)
genComponents
(
bindingComponents
,
context
)
newline
()
if
(
!
inline
)
{
push
(
`export `
)
...
...
packages/uni-mp-compiler/src/compile.ts
浏览文件 @
c83c6ceb
...
...
@@ -56,7 +56,16 @@ export function baseCompile(template: string, options: CompilerOptions = {}) {
),
})
)
const
result
=
extend
(
generate
(
ast
,
context
.
scope
,
options
),
{
ast
})
const
result
=
extend
(
generate
(
extend
(
ast
,
{
scope
:
context
.
scope
,
bindingComponents
:
context
.
bindingComponents
,
}),
options
),
{
ast
}
)
if
(
options
.
filename
&&
options
.
miniProgram
?.
emitFile
)
{
genTemplate
(
ast
,
{
filename
:
options
.
filename
,
...
...
packages/uni-mp-compiler/src/errors.ts
浏览文件 @
c83c6ceb
...
...
@@ -5,6 +5,9 @@ export const enum MPErrorCodes {
X_V_BIND_DYNAMIC_ARGUMENT
,
X_V_BIND_MODIFIER_PROP
,
X_V_BIND_MODIFIER_ATTR
,
X_V_IS_NOT_SUPPORTED
,
X_NOT_SUPPORTED
,
X_DYNAMIC_COMPONENT_NOT_SUPPORTED
,
}
export
const
errorMessages
:
Record
<
number
,
string
>
=
{
...
...
@@ -15,4 +18,8 @@ export const errorMessages: Record<number, string> = {
'
v-bind:[name]="" is not supported.
'
,
[
MPErrorCodes
.
X_V_BIND_MODIFIER_PROP
]:
'
v-bind .prop is not supported
'
,
[
MPErrorCodes
.
X_V_BIND_MODIFIER_ATTR
]:
'
v-bind .attr is not supported
'
,
[
MPErrorCodes
.
X_DYNAMIC_COMPONENT_NOT_SUPPORTED
]:
'
<component is=""/> is not supported
'
,
[
MPErrorCodes
.
X_NOT_SUPPORTED
]:
'
not supported:
'
,
[
MPErrorCodes
.
X_V_IS_NOT_SUPPORTED
]:
'
v-is not supported
'
,
}
packages/uni-mp-compiler/src/options.ts
浏览文件 @
c83c6ceb
import
{
ParserPlugin
}
from
'
@babel/parser
'
import
{
Expression
,
ObjectProperty
,
SpreadElement
}
from
'
@babel/types
'
import
{
BindingMetadata
,
CompilerError
}
from
'
@vue/compiler-core
'
import
{
BindingMetadata
,
CompilerError
,
RootNode
}
from
'
@vue/compiler-core
'
import
IdentifierGenerator
from
'
./identifier
'
import
{
DirectiveTransform
,
NodeTransform
}
from
'
./transform
'
import
{
DirectiveTransform
,
NodeTransform
,
TransformContext
,
}
from
'
./transform
'
import
{
VForOptions
}
from
'
./transforms/vFor
'
export
interface
CodegenRootNode
extends
RootNode
{
scope
:
CodegenScope
bindingComponents
:
TransformContext
[
'
bindingComponents
'
]
}
export
interface
ErrorHandlingOptions
{
onWarn
?:
(
warning
:
CompilerError
)
=>
void
onError
?:
(
error
:
CompilerError
)
=>
void
...
...
packages/uni-mp-compiler/src/transform.ts
浏览文件 @
c83c6ceb
...
...
@@ -60,6 +60,11 @@ export interface ErrorHandlingOptions {
onError
?:
(
error
:
CompilerError
)
=>
void
}
export
const
enum
BindingComponentTypes
{
SELF
=
'
self
'
,
SETUP
=
'
setup
'
,
UNKNOWN
=
'
unknown
'
,
}
export
interface
TransformContext
extends
Required
<
Omit
<
TransformOptions
,
'
filename
'
>>
{
selfName
:
string
|
null
...
...
@@ -68,6 +73,10 @@ export interface TransformContext
childIndex
:
number
helpers
:
Map
<
symbol
,
number
>
components
:
Set
<
string
>
bindingComponents
:
Record
<
string
,
{
type
:
BindingComponentTypes
;
name
:
string
}
>
identifiers
:
{
[
name
:
string
]:
number
|
undefined
}
cached
:
number
scopes
:
{
...
...
@@ -269,6 +278,7 @@ export function createTransformContext(
childIndex
:
0
,
helpers
:
new
Map
(),
components
:
new
Set
(),
bindingComponents
:
Object
.
create
(
null
),
cached
:
0
,
identifiers
,
scope
:
rootScope
,
...
...
packages/uni-mp-compiler/src/transforms/transformElement.ts
浏览文件 @
c83c6ceb
import
{
camelize
,
capitalize
}
from
'
@vue/shared
'
import
{
NodeTypes
,
ElementTypes
,
...
...
@@ -8,10 +9,19 @@ import {
TemplateLiteral
,
Property
,
ExpressionNode
,
isCoreComponent
,
BindingTypes
,
UNREF
,
toValidAssetId
,
findDir
,
}
from
'
@vue/compiler-core
'
import
{
errorMessages
,
MPErrorCodes
}
from
'
../errors
'
import
{
NodeTransform
,
TransformContext
}
from
'
../transform
'
import
{
BindingComponentTypes
,
NodeTransform
,
TransformContext
,
}
from
'
../transform
'
export
interface
DirectiveTransformResult
{
props
:
Property
[]
...
...
@@ -31,7 +41,10 @@ export const transformElement: NodeTransform = (node, context) => {
)
{
return
}
const
isComponent
=
node
.
tagType
===
ElementTypes
.
COMPONENT
if
(
isComponent
)
{
processComponent
(
node
,
context
)
}
const
{
props
}
=
node
if
(
props
.
length
>
0
)
{
processProps
(
node
,
context
)
...
...
@@ -39,6 +52,122 @@ export const transformElement: NodeTransform = (node, context) => {
}
}
function
processComponent
(
node
:
ElementNode
,
context
:
TransformContext
)
{
const
{
tag
}
=
node
if
(
context
.
bindingComponents
[
tag
])
{
return
}
// 1. dynamic component
if
(
isComponentTag
(
tag
))
{
return
context
.
onError
(
createCompilerError
(
MPErrorCodes
.
X_DYNAMIC_COMPONENT_NOT_SUPPORTED
,
node
.
loc
,
errorMessages
)
)
}
if
(
findDir
(
node
,
'
is
'
))
{
return
context
.
onError
(
createCompilerError
(
MPErrorCodes
.
X_V_IS_NOT_SUPPORTED
,
node
.
loc
,
errorMessages
)
)
}
// TODO not supported
// const isProp = findProp(node, 'is')
// if (isProp) {
// }
// 2. built-in components (Teleport, Transition, KeepAlive, Suspense...)
const
builtIn
=
isCoreComponent
(
tag
)
||
context
.
isBuiltInComponent
(
tag
)
if
(
builtIn
)
{
return
context
.
onError
(
createCompilerError
(
MPErrorCodes
.
X_NOT_SUPPORTED
,
node
.
loc
,
errorMessages
,
tag
)
)
}
// 3. user component (from setup bindings)
const
fromSetup
=
resolveSetupReference
(
tag
,
context
)
if
(
fromSetup
)
{
return
(
context
.
bindingComponents
[
tag
]
=
{
name
:
fromSetup
,
type
:
BindingComponentTypes
.
SETUP
,
})
}
const
dotIndex
=
tag
.
indexOf
(
'
.
'
)
if
(
dotIndex
>
0
)
{
return
context
.
onError
(
createCompilerError
(
MPErrorCodes
.
X_NOT_SUPPORTED
,
node
.
loc
,
errorMessages
,
tag
)
)
}
// 4. Self referencing component (inferred from filename)
if
(
context
.
selfName
&&
capitalize
(
camelize
(
tag
))
===
context
.
selfName
)
{
return
(
context
.
bindingComponents
[
tag
]
=
{
name
:
toValidAssetId
(
tag
,
`component`
),
type
:
BindingComponentTypes
.
SELF
,
})
}
// 5. user component (resolve)
context
.
bindingComponents
[
tag
]
=
{
name
:
toValidAssetId
(
tag
,
`component`
),
type
:
BindingComponentTypes
.
UNKNOWN
,
}
}
function
resolveSetupReference
(
name
:
string
,
context
:
TransformContext
)
{
const
bindings
=
context
.
bindingMetadata
if
(
!
bindings
||
bindings
.
__isScriptSetup
===
false
)
{
return
}
const
camelName
=
camelize
(
name
)
const
PascalName
=
capitalize
(
camelName
)
const
checkType
=
(
type
:
BindingTypes
)
=>
{
if
(
bindings
[
name
]
===
type
)
{
return
name
}
if
(
bindings
[
camelName
]
===
type
)
{
return
camelName
}
if
(
bindings
[
PascalName
]
===
type
)
{
return
PascalName
}
}
const
fromConst
=
checkType
(
BindingTypes
.
SETUP_CONST
)
if
(
fromConst
)
{
return
context
.
inline
?
// in inline mode, const setup bindings (e.g. imports) can be used as-is
fromConst
:
`$setup[
${
JSON
.
stringify
(
fromConst
)}
]`
}
const
fromMaybeRef
=
checkType
(
BindingTypes
.
SETUP_LET
)
||
checkType
(
BindingTypes
.
SETUP_REF
)
||
checkType
(
BindingTypes
.
SETUP_MAYBE_REF
)
if
(
fromMaybeRef
)
{
return
context
.
inline
?
// setup scope bindings that may be refs need to be unrefed
`
${
context
.
helperString
(
UNREF
)}
(
${
fromMaybeRef
}
)`
:
`$setup[
${
JSON
.
stringify
(
fromMaybeRef
)}
]`
}
}
function
processProps
(
node
:
ElementNode
,
context
:
TransformContext
)
{
const
{
tag
,
props
}
=
node
const
isComponent
=
node
.
tagType
===
ElementTypes
.
COMPONENT
...
...
@@ -108,81 +237,11 @@ function processProps(node: ElementNode, context: TransformContext) {
if
(
directiveTransform
)
{
prop
.
exp
=
directiveTransform
(
prop
,
node
,
context
).
props
[
0
]
.
value
as
ExpressionNode
// const { arg } = prop
// if (arg && arg.type === NodeTypes.SIMPLE_EXPRESSION && prop.exp) {
// const { content } = arg
// if (content === 'class') {
// hasClassBinding = true
// processClass(prop, props, context)
// } else if (content === 'style') {
// hasStyleBinding = true
// processStyle(prop, props, context)
// }
// }
}
}
}
// remove static class and static style
// if (hasClassBinding) {
// const staticClassPropIndex = findStaticClassIndex(props)
// if (staticClassPropIndex > -1) {
// props.splice(staticClassPropIndex, 1)
// }
// }
// if (hasStyleBinding) {
// const staticStylePropIndex = findStaticStyleIndex(props)
// if (staticStylePropIndex > -1) {
// props.splice(staticStylePropIndex, 1)
// }
// }
}
function
isComponentTag
(
tag
:
string
)
{
return
tag
[
0
].
toLowerCase
()
+
tag
.
slice
(
1
)
===
'
component
'
}
// function findStaticClassIndex(props: (AttributeNode | DirectiveNode)[]) {
// return props.findIndex((prop) => prop.name === 'class')
// }
// function findStaticStyleIndex(props: (AttributeNode | DirectiveNode)[]) {
// return props.findIndex((prop) => prop.name === 'style')
// }
// function processClass(
// classBindingProp: DirectiveNode,
// props: (AttributeNode | DirectiveNode)[],
// context: TransformContext
// ) {
// if (!classBindingProp.exp) {
// return
// }
// const staticClassPropIndex = findStaticClassIndex(props)
// const staticClass =
// staticClassPropIndex > -1
// ? (props[staticClassPropIndex] as AttributeNode).value
// : ''
// const expr = parseExpr(classBindingProp.exp, context)
// if (!expr) {
// return
// }
// console.log(staticClass)
// if (isObjectExpression(expr)) {
// classBindingProp.exp = createSimpleExpression(
// genBabelExpr(createClassBindingArrayExpression(expr))
// )
// }
// }
// function processStyle(
// styleBindingPropprop: DirectiveNode,
// props: (AttributeNode | DirectiveNode)[],
// context: TransformContext
// ) {
// const staticStylePropIndex = findStaticStyleIndex(props)
// const staticStyle =
// staticStylePropIndex > -1
// ? (props[staticStylePropIndex] as AttributeNode).value
// : ''
// if (staticStyle) {
// console.log(staticStyle)
// }
// }
packages/uni-mp-vite/__tests__/test.js
浏览文件 @
c83c6ceb
...
...
@@ -14,3 +14,5 @@ console.log(
depth
:
null
,
})
)
// import a from 'a.vue'
packages/uni-mp-vite/package.json
浏览文件 @
c83c6ceb
...
...
@@ -18,5 +18,8 @@
"test"
:
"echo
\"
Error: no test specified
\"
&& exit 1"
},
"license"
:
"Apache-2.0"
,
"dependencies"
:
{
"magic-string"
:
"^0.25.7"
},
"gitHead"
:
"1efa8efd0a9eddeabdba75c020d015ebf31b8177"
}
packages/uni-mp-vite/src/index.ts
浏览文件 @
c83c6ceb
import
{
uniMiniProgramPlugin
,
UniMiniProgramPluginOptions
}
from
'
./plugin
'
import
{
uniComponentPlugin
}
from
'
./plugins/component
'
import
{
uniMainJsPlugin
}
from
'
./plugins/mainJs
'
import
{
uniManifestJsonPlugin
}
from
'
./plugins/manifestJson
'
import
{
uniPagesJsonPlugin
}
from
'
./plugins/pagesJson
'
...
...
@@ -11,5 +12,6 @@ export default (options: UniMiniProgramPluginOptions) => {
uniPagesJsonPlugin
(
options
),
uniVirtualPlugin
(
options
),
uniMiniProgramPlugin
(
options
),
uniComponentPlugin
(),
]
}
packages/uni-mp-vite/src/plugins/component.ts
0 → 100644
浏览文件 @
c83c6ceb
import
path
from
'
path
'
import
{
Plugin
}
from
'
vite
'
import
{
EXTNAME_VUE
,
parseVueRequest
,
findVueComponentImports
,
}
from
'
@dcloudio/uni-cli-shared
'
import
MagicString
from
'
magic-string
'
import
{
virtualComponentPath
}
from
'
./virtual
'
export
function
uniComponentPlugin
():
Plugin
{
return
{
name
:
'
vite:uni-mp-component
'
,
async
transform
(
code
,
id
)
{
const
{
filename
,
query
}
=
parseVueRequest
(
id
)
if
(
query
.
vue
)
{
return
null
}
if
(
!
EXTNAME_VUE
.
includes
(
path
.
extname
(
filename
)))
{
return
null
}
const
vueComponentImports
=
await
findVueComponentImports
(
code
,
id
,
this
.
resolve
)
if
(
!
vueComponentImports
.
length
)
{
return
null
}
const
s
=
new
MagicString
(
code
)
const
rewriteImports
:
string
[]
=
[]
vueComponentImports
.
forEach
(({
n
,
ss
,
se
})
=>
{
s
.
remove
(
ss
,
se
)
rewriteImports
.
push
(
`import('
${
virtualComponentPath
(
n
!
)}
')`
)
})
s
.
prepend
(
`if(!Math){
${
rewriteImports
.
join
(
'
;
'
)}
}`
)
return
s
.
toString
()
},
}
}
packages/uni-vue/src/componentOptions/hooks.ts
浏览文件 @
c83c6ceb
import
{
invokeHook
}
from
'
@dcloudio/uni-core
'
import
{
ON_LOAD
,
ON_SHOW
}
from
'
@dcloudio/uni-shared
'
import
{
LINEFEED
,
ON_LOAD
,
ON_SHOW
}
from
'
@dcloudio/uni-shared
'
import
{
isArray
,
isFunction
}
from
'
@vue/shared
'
import
{
...
...
@@ -49,7 +49,7 @@ export function initHooks(
invokeHook
(
publicThis
,
ON_SHOW
)
})
}
catch
(
e
:
any
)
{
console
.
error
(
e
.
message
+
'
\n
'
+
e
.
stack
)
console
.
error
(
e
.
message
+
LINEFEED
+
e
.
stack
)
}
}
}
yarn.lock
浏览文件 @
c83c6ceb
...
...
@@ -4616,7 +4616,7 @@ es-abstract@^1.19.1:
string.prototype.trimstart "^1.0.4"
unbox-primitive "^1.0.1"
es-module-lexer@^0.9.0:
es-module-lexer@^0.9.0
, es-module-lexer@^0.9.3
:
version "0.9.3"
resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19"
integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录