提交 c83c6ceb 编写于 作者: fxy060608's avatar fxy060608

wip(mp): transform static import to dynamic import

上级 236ad155
......@@ -5680,7 +5680,8 @@ var serviceContext = (function (vue) {
},
};
const API_CLOSE_AUTH_VIEW = 'closeAuthView';
const API_GET_CHECK_BOX_STATE = 'getCheckBoxState';
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({
code: '30008',
message: '用户点击了自定义按钮',
index,
provider: button.provider,
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,
......
......@@ -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",
......
......@@ -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)
}
}
......
......@@ -24,7 +24,7 @@ interface EasycomCustom {
[key: string]: string
}
const debugEasycom = debug('uni:easycom')
const debugEasycom = debug('vite:uni:easycom')
const easycoms: EasycomMatcher[] = []
......
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
}
export * from './event'
export { findVueComponentImports } from './imports'
......@@ -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"));
......
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,
})
)
})
})
})
......@@ -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,
......
......@@ -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(
......
......@@ -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: CodegenRootNode,
{
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 `)
......
......@@ -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,
......
......@@ -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',
}
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
......
......@@ -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,
......
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)
// }
// }
......@@ -14,3 +14,5 @@ console.log(
depth: null,
})
)
// import a from 'a.vue'
......@@ -18,5 +18,8 @@
"test": "echo \"Error: no test specified\" && exit 1"
},
"license": "Apache-2.0",
"dependencies": {
"magic-string": "^0.25.7"
},
"gitHead": "1efa8efd0a9eddeabdba75c020d015ebf31b8177"
}
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(),
]
}
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()
},
}
}
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)
}
}
}
......@@ -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.
先完成此消息的编辑!
想要评论请 注册