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

feat(uni_modules): support exports

上级 ae8b753a
......@@ -2,6 +2,7 @@ import {
defineUniMainJsPlugin,
MANIFEST_JSON_JS,
PAGES_JSON_JS,
UNI_MODULES_EXPORTS,
} from '@dcloudio/uni-cli-shared'
import { APP_CSS_JS } from './appCss'
......@@ -20,7 +21,7 @@ export function uniMainJsPlugin({
if (opts.filter(id)) {
if (renderer !== 'native') {
return {
code: `import './${PAGES_JSON_JS}';import('${APP_CSS_JS}').then(()=>{})`,
code: `import './${PAGES_JSON_JS}';import '${UNI_MODULES_EXPORTS}';import('${APP_CSS_JS}').then(()=>{})`,
map: { mappings: '' },
}
}
......@@ -30,13 +31,13 @@ export function uniMainJsPlugin({
: createLegacyApp(code)
return {
code:
`import './${MANIFEST_JSON_JS}';\nimport './${PAGES_JSON_JS}';\n` +
`import './${MANIFEST_JSON_JS}';\nimport './${PAGES_JSON_JS}';\nimport '${UNI_MODULES_EXPORTS}';\n` +
code,
map: { mappings: '' },
}
}
return {
code: `import './${PAGES_JSON_JS}';`,
code: `import './${PAGES_JSON_JS}';import '${UNI_MODULES_EXPORTS}';`,
map: { mappings: '' },
}
}
......
import { defineUniMainJsPlugin, PAGES_JSON_JS } from '@dcloudio/uni-cli-shared'
import {
defineUniMainJsPlugin,
PAGES_JSON_JS,
UNI_MODULES_EXPORTS,
} from '@dcloudio/uni-cli-shared'
export function uniMainJsPlugin() {
return defineUniMainJsPlugin((opts) => {
......@@ -11,7 +15,9 @@ export function uniMainJsPlugin() {
? createApp(code)
: createLegacyApp(code)
return {
code: `import './${PAGES_JSON_JS}';` + code,
code:
`import './${PAGES_JSON_JS}';import '${UNI_MODULES_EXPORTS}';` +
code,
map: { mappings: '' },
}
}
......
import { parseExports } from '../src/vite/plugins/uniModules'
describe('uni_modules:exports', () => {
test('parseExports', () => {
expect(
parseExports('app', `@/uni_modules/uni-getbatteryinfo`, {
uni: 'getBatteryInfo',
})
).toEqual([
["import getBatteryInfo from '@/uni_modules/uni-getbatteryinfo'"],
['uni.getBatteryInfo = getBatteryInfo'],
])
expect(
parseExports('app', `@/uni_modules/uni-getbatteryinfo`, {
uni: ['getBatteryInfo'],
})
).toEqual([
["import { getBatteryInfo } from '@/uni_modules/uni-getbatteryinfo'"],
['uni.getBatteryInfo = getBatteryInfo'],
])
expect(
parseExports('app', `@/uni_modules/uni-location`, {
uni: ['openLocation', 'chooseLocation'],
})
).toEqual([
[
"import { openLocation, chooseLocation } from '@/uni_modules/uni-location'",
],
[
'uni.openLocation = openLocation',
'uni.chooseLocation = chooseLocation',
],
])
expect(
parseExports('app', `@/uni_modules/uni-capturescreen`, {
uni: {
onUserCaptureScreen: 'onCaptureScreen',
offUserCaptureScreen: 'offUserCaptureScreen',
},
})
).toEqual([
[
"import { onCaptureScreen as onUserCaptureScreen, offUserCaptureScreen } from '@/uni_modules/uni-capturescreen'",
],
[
'uni.onUserCaptureScreen = onUserCaptureScreen',
'uni.offUserCaptureScreen = offUserCaptureScreen',
],
])
})
test('parseExports with platform', () => {
expect(
parseExports('web', `@/uni_modules/uni-getbatteryinfo`, {
uni: 'getBatteryInfo1',
web: {
uni: 'getBatteryInfo',
},
})
).toEqual([
["import getBatteryInfo from '@/uni_modules/uni-getbatteryinfo'"],
['uni.getBatteryInfo = getBatteryInfo'],
])
expect(
parseExports('web', `@/uni_modules/uni-getbatteryinfo`, {
uni: 'getBatteryInfo1',
web: false,
})
).toEqual([[], []])
expect(
parseExports('web', `@/uni_modules/uni-location`, {
uni: ['openLocation'],
web: {
uni: ['chooseLocation'],
},
})
).toEqual([
["import { chooseLocation } from '@/uni_modules/uni-location'"],
['uni.chooseLocation = chooseLocation'],
])
})
})
......@@ -17,6 +17,7 @@ export const extensions = [
'.json',
].concat(EXTNAME_VUE)
export const UNI_MODULES_EXPORTS = '\0uni-modules-exports'
export const PAGES_JSON_JS = 'pages-json-js'
export const MANIFEST_JSON_JS = 'manifest-json-js'
export const JSON_JS_MAP = {
......
......@@ -5,6 +5,7 @@ export * from './mainJs'
export * from './jsonJs'
export * from './console'
export * from './dynamicImportPolyfill'
export { uniModulesExportsPlugin } from './uniModules'
export { assetPlugin, getAssetHash } from './vitejs/plugins/asset'
export {
......
......@@ -23,6 +23,7 @@ import {
isJsFile,
isAssignmentExpression,
} from '../utils'
import { UNI_MODULES_EXPORTS } from '../../constants'
interface Scope {
parent: Scope
......@@ -83,8 +84,11 @@ export function uniViteInjectPlugin(
// 确保在 commonjs 之后,否则会混合 es6 module 与 cjs 的代码,导致 commonjs 失效
enforce: 'post',
transform(code, id) {
if (!filter(id)) return null
if (!isJsFile(id)) return null
// 硬编码支持了uni_modules_exports
if (id !== UNI_MODULES_EXPORTS) {
if (!filter(id)) return null
if (!isJsFile(id)) return null
}
debugInjectTry(id)
if (code.search(firstpass) === -1) return null
if (sep !== '/') id = id.split(sep).join('/')
......
import path from 'path'
import fs from 'fs-extra'
import type { Plugin } from 'vite'
import { recursive } from 'merge'
import { isArray, isPlainObject, isString } from '@vue/shared'
import { UNI_MODULES_EXPORTS } from '../../constants'
import { parseJson } from '../../json'
export function uniModulesExportsPlugin(): Plugin {
return {
name: 'uni:modules:exports',
resolveId(id) {
if (id === UNI_MODULES_EXPORTS) {
return UNI_MODULES_EXPORTS
}
},
load(id) {
if (id !== UNI_MODULES_EXPORTS) {
return
}
const uniModulesDir = path.resolve(
process.env.UNI_INPUT_DIR,
'uni_modules'
)
if (!fs.existsSync(uniModulesDir)) {
return ''
}
const importCodes: string[] = []
const assignCodes: string[] = []
fs.readdirSync(uniModulesDir).forEach((uniModuleDir) => {
const pkgPath = path.resolve(
uniModulesDir,
uniModuleDir,
'package.json'
)
if (!fs.existsSync(pkgPath)) {
return
}
const exports = parseJson(fs.readFileSync(pkgPath, 'utf8'))?.uni_modules
?.exports as Exports | undefined
if (exports) {
const [exportsImportCodes, exportsAssignCodes] = parseExports(
process.env.UNI_PLATFORM === 'h5'
? 'web'
: process.env.UNI_PLATFORM,
`@/uni_modules/${uniModuleDir}`,
exports
)
importCodes.push(...exportsImportCodes)
assignCodes.push(...exportsAssignCodes)
}
})
if (!importCodes.length) {
return ''
}
return `${importCodes.join('\n')}
${assignCodes.join('\n')}`
},
}
}
type Define = string | string[] | Record<string, string>
type Defines = {
[name: string]: Define
}
interface Exports {
[name: string]: Define | Defines | false
}
export function parseExports(
platform: UniApp.PLATFORM,
source: string,
exports: Exports = {}
): [string[], string[]] {
const rootDefines: Defines = {}
Object.keys(exports).forEach((name) => {
if (name.startsWith('uni')) {
rootDefines[name] = exports[name] as Define
}
})
const platformDefines = exports[platform] as false | Defines
// 该平台不支持
if (platformDefines === false) {
return [[], []]
}
return parseDefines(source, recursive(true, rootDefines, platformDefines))
}
export function parseDefines(
source: string,
defines: Defines = {}
): [string[], string[]] {
const importCodes: string[] = []
const assignCodes: string[] = []
Object.keys(defines).forEach((name) => {
const [defineImportCodes, defineAssignCodes] = parseDefine(
source,
name,
defines[name]
)
importCodes.push(...defineImportCodes)
assignCodes.push(...defineAssignCodes)
})
return [importCodes, assignCodes]
}
/**
* uni:'getBatteryInfo'
* import getBatteryInfo from '..'
*
* uni:['getBatteryInfo']
* import { getBatteryInfo } from '..'
*
* uni:['openLocation','chooseLocation']
* import { openLocation, chooseLocation } from '..'
*
* uni:{
* onUserCaptureScreen: "onCaptureScreen"
* offUserCaptureScreen: "offCaptureScreen"
* }
*
* uni.getBatteryInfo = getBatteryInfo
* @param source
* @param globalObject
* @param define
* @returns
*/
function parseDefine(
source: string,
globalObject: string,
define: Define
): [string[], string[]] {
const importCodes: string[] = []
const assignCodes: string[] = []
if (isString(define)) {
importCodes.push(`import ${define} from '${source}'`)
assignCodes.push(`${globalObject}.${define} = ${define}`)
} else if (isArray(define)) {
importCodes.push(`import { ${define.join(', ')} } from '${source}'`)
define.forEach((d) => {
assignCodes.push(`${globalObject}.${d} = ${d}`)
})
} else if (isPlainObject(define)) {
const keys = Object.keys(define)
const specifiers: string[] = []
keys.forEach((d) => {
if (d !== define[d]) {
specifiers.push(`${define[d]} as ${d}`)
} else {
specifiers.push(d)
}
assignCodes.push(`${globalObject}.${d} = ${d}`)
})
importCodes.push(`import { ${specifiers.join(', ')} } from '${source}'`)
}
return [importCodes, assignCodes]
}
import path from 'path'
import { EXTNAME_JS_RE, EXTNAME_VUE } from '../../constants'
import {
EXTNAME_JS_RE,
EXTNAME_VUE,
UNI_MODULES_EXPORTS,
} from '../../constants'
export interface VueQuery {
vue?: boolean
......@@ -62,6 +66,10 @@ export const cleanUrl = (url: string) =>
url.replace(hashRE, '').replace(queryRE, '')
export function isJsFile(id: string) {
// inject 使用了isJsFile 判断。uni_modules_exports 中注入使用了 uni,在小程序平台,inject 需要注入 uni 对象
if (id === UNI_MODULES_EXPORTS) {
return true
}
const isJs = EXTNAME_JS_RE.test(id)
if (isJs) {
return true
......
......@@ -2,6 +2,7 @@ import {
defineUniMainJsPlugin,
isSsr,
PAGES_JSON_JS,
UNI_MODULES_EXPORTS,
} from '@dcloudio/uni-cli-shared'
import { isSSR, isSsrManifest } from '../utils'
......@@ -26,7 +27,7 @@ export function uniMainJsPlugin() {
? createSSRServerApp(code)
: createSSRClientApp(code)
}
code = `import './${PAGES_JSON_JS}';${code}`
code = `import './${PAGES_JSON_JS}';import '${UNI_MODULES_EXPORTS}';${code}`
return {
code,
map: this.getCombinedSourcemap(),
......
......@@ -3,6 +3,7 @@ import {
PAGES_JSON_JS,
parseProgram,
transformDynamicImports,
UNI_MODULES_EXPORTS,
updateMiniProgramGlobalComponents,
withSourcemap,
} from '@dcloudio/uni-cli-shared'
......@@ -46,7 +47,7 @@ export function uniMainJsPlugin(
})
return {
code:
`import '\0plugin-vue:export-helper';import 'uni-mp-runtime';import './${PAGES_JSON_JS}';` +
`import '\0plugin-vue:export-helper';import 'uni-mp-runtime';import './${PAGES_JSON_JS}';import '${UNI_MODULES_EXPORTS}';` +
code,
map,
}
......
......@@ -12,6 +12,7 @@ import {
initModuleAlias,
initPreContext,
resolveSourceMapPath,
uniModulesExportsPlugin,
} from '@dcloudio/uni-cli-shared'
import { createConfig } from './config'
......@@ -85,7 +86,7 @@ export default function uniPlugin(
initPreContext(options.platform, process.env.UNI_CUSTOM_CONTEXT)
const plugins: Plugin[] = []
const plugins: Plugin[] = [uniModulesExportsPlugin()]
// 仅限 h5
if (options.viteLegacyOptions && options.platform === 'h5') {
plugins.push(
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册