From 80394f201f8fae0437c774d03c8239cd43164270 Mon Sep 17 00:00:00 2001 From: fxy060608 Date: Wed, 9 Jun 2021 21:23:24 +0800 Subject: [PATCH] feat: add uni-h5-vite --- .eslintrc.js | 2 +- package.json | 2 +- packages/playground/ssr/package.json | 1 + packages/size-check/vite.config.ts | 4 +- packages/uni-cli-shared/src/index.ts | 1 + packages/uni-cli-shared/src/vite/features.ts | 289 ++++++++++++++++ packages/uni-cli-shared/src/vite/index.ts | 9 + packages/uni-cli-shared/src/vite/utils.ts | 8 + packages/uni-h5-vite/LICENSE | 202 ++++++++++++ packages/uni-h5-vite/build.json | 0 packages/uni-h5-vite/dist/index.js | 25 ++ packages/uni-h5-vite/dist/plugins/css.js | 45 +++ .../uni-h5-vite/dist/plugins/cssScoped.js | 60 ++++ packages/uni-h5-vite/dist/plugins/mainJs.js | 57 ++++ .../uni-h5-vite/dist/plugins/manifestJson.js | 87 +++++ .../uni-h5-vite/dist/plugins/pagesJson.js | 241 ++++++++++++++ .../uni-h5-vite/dist/plugins/resolveId.js | 37 +++ packages/uni-h5-vite/dist/utils/index.js | 13 + packages/uni-h5-vite/dist/utils/ssr.js | 120 +++++++ packages/uni-h5-vite/package.json | 28 ++ packages/uni-h5-vite/src/index.ts | 26 ++ .../src}/plugins/css.ts | 18 +- .../src}/plugins/cssScoped.ts | 12 +- .../src}/plugins/mainJs.ts | 33 +- .../src}/plugins/manifestJson.ts | 25 +- packages/uni-h5-vite/src/plugins/pagesJson.ts | 312 ++++++++++++++++++ packages/uni-h5-vite/src/plugins/resolveId.ts | 43 +++ packages/uni-h5-vite/src/utils/index.ts | 1 + packages/uni-h5-vite/src/utils/ssr.ts | 146 ++++++++ packages/uni-h5-vite/tsconfig.json | 7 + packages/uni-h5-vue/package.json | 2 +- packages/uni-h5/dist/uni-h5.cjs.js | 1 + packages/uni-h5/dist/uni-h5.es.js | 8 +- packages/uni-h5/lib/resolve-id.js | 28 ++ packages/uni-h5/package.json | 4 - .../src/framework/setup/provide/page.ts | 1 + packages/uni-shared/dist/uni-shared.cjs.js | 4 + packages/uni-shared/dist/uni-shared.d.ts | 2 + packages/uni-shared/dist/uni-shared.es.js | 4 + packages/uni-shared/src/vdom/Node.ts | 7 + packages/vite-plugin-uni/src/cli/index.ts | 6 +- packages/vite-plugin-uni/src/cli/utils.ts | 2 + .../src/configResolved/plugins/easycom.ts | 3 +- .../src/configResolved/plugins/index.ts | 31 +- .../src/configResolved/plugins/resolveId.ts | 74 +---- .../vite-plugin-uni/src/utils/constants.ts | 39 --- packages/vite-plugin-uni/src/utils/index.ts | 1 - packages/vite-plugin-uni/src/utils/plugin.ts | 3 +- yarn.lock | 3 + 49 files changed, 1898 insertions(+), 179 deletions(-) create mode 100644 packages/uni-cli-shared/src/vite/features.ts create mode 100644 packages/uni-cli-shared/src/vite/index.ts create mode 100644 packages/uni-cli-shared/src/vite/utils.ts create mode 100755 packages/uni-h5-vite/LICENSE create mode 100644 packages/uni-h5-vite/build.json create mode 100644 packages/uni-h5-vite/dist/index.js create mode 100644 packages/uni-h5-vite/dist/plugins/css.js create mode 100644 packages/uni-h5-vite/dist/plugins/cssScoped.js create mode 100644 packages/uni-h5-vite/dist/plugins/mainJs.js create mode 100644 packages/uni-h5-vite/dist/plugins/manifestJson.js create mode 100644 packages/uni-h5-vite/dist/plugins/pagesJson.js create mode 100644 packages/uni-h5-vite/dist/plugins/resolveId.js create mode 100644 packages/uni-h5-vite/dist/utils/index.js create mode 100644 packages/uni-h5-vite/dist/utils/ssr.js create mode 100644 packages/uni-h5-vite/package.json create mode 100644 packages/uni-h5-vite/src/index.ts rename packages/{vite-plugin-uni/src/configResolved => uni-h5-vite/src}/plugins/css.ts (68%) rename packages/{vite-plugin-uni/src/configResolved => uni-h5-vite/src}/plugins/cssScoped.ts (78%) rename packages/{vite-plugin-uni/src/configResolved => uni-h5-vite/src}/plugins/mainJs.ts (69%) rename packages/{vite-plugin-uni/src/configResolved => uni-h5-vite/src}/plugins/manifestJson.ts (79%) create mode 100644 packages/uni-h5-vite/src/plugins/pagesJson.ts create mode 100644 packages/uni-h5-vite/src/plugins/resolveId.ts create mode 100644 packages/uni-h5-vite/src/utils/index.ts create mode 100644 packages/uni-h5-vite/src/utils/ssr.ts create mode 100644 packages/uni-h5-vite/tsconfig.json create mode 100644 packages/uni-h5/lib/resolve-id.js delete mode 100644 packages/vite-plugin-uni/src/utils/constants.ts diff --git a/.eslintrc.js b/.eslintrc.js index 4bb94069c9..d91fd94887 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -44,7 +44,7 @@ module.exports = { // Packages targeting Node { files: [ - 'packages/{uni-cli-shared,vite-plugin-uni}/**', + 'packages/{uni-cli-shared,uni-h5-vite,vite-plugin-uni}/**', 'packages/*/vite.config.ts', ], rules: { diff --git a/package.json b/package.json index c61615a388..28254bab31 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ ], "scripts": { "build": "node scripts/build.js", - "build:h5": "node scripts/build.js uni-app uni-cli-shared uni-h5 uni-i18n uni-shared vite-plugin-uni", + "build:h5": "node scripts/build.js uni-app uni-cli-shared uni-h5 uni-i18n uni-shared uni-h5-vite vite-plugin-uni", "size": "npm run build size-check", "lint": "eslint packages/*/src/**/*.ts", "format": "prettier --write --parser typescript \"packages/**/*.ts?(x)\"", diff --git a/packages/playground/ssr/package.json b/packages/playground/ssr/package.json index 09f9bab13b..17e4dbe363 100644 --- a/packages/playground/ssr/package.json +++ b/packages/playground/ssr/package.json @@ -23,6 +23,7 @@ }, "devDependencies": { "@dcloudio/uni-cli-shared": "../../uni-cli-shared", + "@dcloudio/uni-h5-vite": "../../uni-h5-vite", "@dcloudio/vite-plugin-uni": "../../vite-plugin-uni", "@vitejs/plugin-vue": "^1.2.3", "@vue/compiler-sfc": "^3.1.0-beta.7", diff --git a/packages/size-check/vite.config.ts b/packages/size-check/vite.config.ts index 7074d1103e..b8cec30422 100644 --- a/packages/size-check/vite.config.ts +++ b/packages/size-check/vite.config.ts @@ -1,6 +1,8 @@ import path from 'path' +import uniH5VitePlugins from '@dcloudio/uni-h5-vite' import uni from '@dcloudio/vite-plugin-uni' +process.env.UNI_CLI_CONTEXT = __dirname /** * @type {import('vite').UserConfig} */ @@ -20,5 +22,5 @@ export default { }, }, - plugins: [uni({ viteLegacyOptions: false })], + plugins: [...uniH5VitePlugins, uni({ viteLegacyOptions: false })], } diff --git a/packages/uni-cli-shared/src/index.ts b/packages/uni-cli-shared/src/index.ts index d44b62ffe3..32ebc1c714 100644 --- a/packages/uni-cli-shared/src/index.ts +++ b/packages/uni-cli-shared/src/index.ts @@ -2,6 +2,7 @@ export * from './ssr' export * from './url' export * from './deps' export * from './json' +export * from './vite' export * from './utils' export * from './constants' export * from './preprocess' diff --git a/packages/uni-cli-shared/src/vite/features.ts b/packages/uni-cli-shared/src/vite/features.ts new file mode 100644 index 0000000000..dc39cd142e --- /dev/null +++ b/packages/uni-cli-shared/src/vite/features.ts @@ -0,0 +1,289 @@ +import fs from 'fs' +import path from 'path' +import { ConfigEnv } from 'vite' +import { extend, isArray, isString } from '@vue/shared' + +interface ProjectFeatures {} +interface PagesFeatures { + nvue: boolean + pages: boolean + tabBar: boolean + tabBarMidButton: boolean + topWindow: boolean + leftWindow: boolean + rightWindow: boolean + navigationBar: boolean + pullDownRefresh: boolean + navigationBarButtons: boolean + navigationBarSearchInput: boolean + navigationBarTransparent: boolean +} +interface ManifestFeatures { + wx: boolean + wxs: boolean + rpx: boolean + promise: boolean + longpress: boolean + routerMode: '"hash"' | '"history"' + i18nEn: boolean + i18nEs: boolean + i18nFr: boolean + i18nZhHans: boolean + i18nZhHant: boolean + vueOptionsApi: boolean + vueProdDevTools: boolean +} + +function initProjectFeature({ command }: InitFeaturesOptions) { + const features: ProjectFeatures = {} + if (command === 'build') { + } + return features +} + +function initPagesFeature({ + pagesJson, + command, + inputDir, + ssr, +}: InitFeaturesOptions): PagesFeatures { + const features: PagesFeatures = { + nvue: true, + pages: true, + tabBar: true, + tabBarMidButton: true, + topWindow: false, + leftWindow: false, + rightWindow: false, + navigationBar: true, + pullDownRefresh: false, + navigationBarButtons: true, + navigationBarSearchInput: true, + navigationBarTransparent: true, + } + + const { tabBar, pages, topWindow, leftWindow, rightWindow, globalStyle } = + pagesJson + // ssr 时强制启用多页面(需要用到router) + if (!ssr && pages && pages.length === 1) { + features.pages = false + } + if (!(tabBar && tabBar.list && tabBar.list.length)) { + features.tabBar = false + features.tabBarMidButton = false + } + if (features.tabBar && !tabBar!.midButton) { + features.tabBarMidButton = false + } + if (topWindow && topWindow.path) { + features.topWindow = true + } + if (leftWindow && leftWindow.path) { + features.leftWindow = true + } + if (rightWindow && rightWindow.path) { + features.rightWindow = true + } + if (globalStyle.enablePullDownRefresh) { + features.pullDownRefresh = true + } else { + if (pages.find((page) => page.style && page.style.enablePullDownRefresh)) { + features.pullDownRefresh = true + } + } + if (command === 'build') { + if ( + !pages.find((page) => + fs.existsSync(path.resolve(inputDir, page.path + '.nvue')) + ) + ) { + features.nvue = false + } + let isNavigationCustom = false + if (globalStyle.navigationBar.style === 'custom') { + isNavigationCustom = true // 全局custom + if (pages.find((page) => page.style.navigationBar.style === 'default')) { + isNavigationCustom = false + } + } else { + // 所有页面均custom + if (pages.every((page) => page.style.navigationBar.style === 'custom')) { + isNavigationCustom = true + } + } + if (isNavigationCustom) { + features.navigationBar = false + features.navigationBarButtons = false + features.navigationBarSearchInput = false + features.navigationBarTransparent = false + } else { + if ( + !pages.find( + (page) => + isArray(page.style.navigationBar.buttons) && + page.style.navigationBar.buttons.length + ) + ) { + features.navigationBarButtons = false + } + if ( + !globalStyle.navigationBar.searchInput && + !pages.find((page) => page.style.navigationBar.searchInput) + ) { + features.navigationBarSearchInput = false + } + if ( + globalStyle.navigationBar.type !== 'transparent' && + !pages.find((page) => page.style.navigationBar.type === 'transparent') + ) { + features.navigationBarTransparent = false + } + } + } + return features +} + +function initManifestFeature({ + manifestJson, + command, + platform, +}: InitFeaturesOptions): ManifestFeatures { + const features: ManifestFeatures = { + wx: false, + wxs: true, + rpx: true, + promise: false, + longpress: true, + routerMode: '"hash"', + i18nEn: true, + i18nEs: true, + i18nFr: true, + i18nZhHans: true, + i18nZhHant: true, + vueOptionsApi: true, + vueProdDevTools: false, + } + + if (command === 'build') { + // TODO 需要预编译一遍? + features.wxs = false + features.longpress = false + } + if ( + manifestJson.h5 && + manifestJson.h5.router && + manifestJson.h5.router.mode === 'history' + ) { + features.routerMode = '"history"' + } + const platformJson = manifestJson[platform] || {} + const manifestFeatures = platformJson.features + if (manifestFeatures) { + const { i18n } = manifestFeatures + if (isArray(i18n)) { + if (!i18n.includes('en')) { + features.i18nEn = false + } + if (!i18n.includes('es')) { + features.i18nEs = false + } + if (!i18n.includes('fr')) { + features.i18nFr = false + } + if (!i18n.includes('zh-Hans')) { + features.i18nZhHans = false + } + if (!i18n.includes('zh-Hant')) { + features.i18nZhHant = false + } + } + } + // TODO other features + return features +} + +export type FEATURE_DEFINES = ReturnType + +interface InitFeaturesOptions { + pagesJson: UniApp.PagesJson + manifestJson: any + inputDir: string + platform: UniApp.PLATFORM + command: ConfigEnv['command'] + ssr: boolean +} + +export function initFeatures(options: InitFeaturesOptions) { + const { + wx, + wxs, + rpx, + nvue, + i18nEn, + i18nEs, + i18nFr, + i18nZhHans, + i18nZhHant, + vueOptionsApi, + vueProdDevTools, + pages, + tabBar, + tabBarMidButton, + promise, + longpress, + routerMode, + topWindow, + leftWindow, + rightWindow, + navigationBar, + pullDownRefresh, + navigationBarButtons, + navigationBarSearchInput, + navigationBarTransparent, + } = extend( + initManifestFeature(options), + initPagesFeature(options), + initProjectFeature(options) + ) + const features = { + // vue + __VUE_OPTIONS_API__: vueOptionsApi, // enable/disable Options API support, default: true + __VUE_PROD_DEVTOOLS__: vueProdDevTools, // enable/disable devtools support in production, default: false + // uni + __UNI_FEATURE_WX__: wx, // 是否启用小程序的组件实例 API,如:selectComponent 等(uni-core/src/service/plugin/appConfig) + __UNI_FEATURE_WXS__: wxs, // 是否启用 wxs 支持,如:getComponentDescriptor 等(uni-core/src/view/plugin/appConfig) + __UNI_FEATURE_RPX__: rpx, // 是否启用运行时 rpx 支持 + __UNI_FEATURE_PROMISE__: promise, // 是否启用旧版本的 promise 支持(即返回[err,res]的格式),默认返回标准 + __UNI_FEATURE_LONGPRESS__: longpress, // 是否启用longpress + __UNI_FEATURE_I18N_EN__: i18nEn, // 是否启用en + __UNI_FEATURE_I18N_ES__: i18nEs, // 是否启用es + __UNI_FEATURE_I18N_FR__: i18nFr, // 是否启用fr + __UNI_FEATURE_I18N_ZH_HANS__: i18nZhHans, // 是否启用zh_Hans + __UNI_FEATURE_I18N_ZH_HANT__: i18nZhHant, // 是否启用zh_Hant + // 以下特性,编译器已自动识别是否需要启用 + __UNI_FEATURE_NVUE__: nvue, // 是否启用nvue + __UNI_FEATURE_ROUTER_MODE__: routerMode, // 路由模式 + __UNI_FEATURE_PAGES__: pages, // 是否多页面 + __UNI_FEATURE_TABBAR__: tabBar, // 是否包含tabBar + __UNI_FEATURE_TABBAR_MIDBUTTON__: tabBarMidButton, // 是否包含midButton + __UNI_FEATURE_TOPWINDOW__: topWindow, // 是否包含topWindow + __UNI_FEATURE_LEFTWINDOW__: leftWindow, // 是否包含leftWindow + __UNI_FEATURE_RIGHTWINDOW__: rightWindow, // 是否包含rightWindow + __UNI_FEATURE_RESPONSIVE__: topWindow || leftWindow || rightWindow, // 是否启用响应式 + __UNI_FEATURE_NAVIGATIONBAR__: navigationBar, // 是否启用标题栏 + __UNI_FEATURE_PULL_DOWN_REFRESH__: pullDownRefresh, // 是否启用下拉刷新 + __UNI_FEATURE_NAVIGATIONBAR_BUTTONS__: navigationBarButtons, // 是否启用标题栏按钮 + __UNI_FEATURE_NAVIGATIONBAR_SEARCHINPUT__: navigationBarSearchInput, // 是否启用标题栏搜索框 + __UNI_FEATURE_NAVIGATIONBAR_TRANSPARENT__: navigationBarTransparent, // 是否启用透明标题栏 + } + // ssr nodejs features + if (options.ssr) { + Object.keys(features).forEach((name) => { + const value = features[name as keyof typeof features] + extend(globalThis, { + [name]: isString(value) ? JSON.parse(value) : value, + }) + }) + } + return features +} diff --git a/packages/uni-cli-shared/src/vite/index.ts b/packages/uni-cli-shared/src/vite/index.ts new file mode 100644 index 0000000000..3a4b5f0059 --- /dev/null +++ b/packages/uni-cli-shared/src/vite/index.ts @@ -0,0 +1,9 @@ +import { Plugin } from 'vite' +export interface UniVitePlugin extends Plugin { + uni?: { + transformEvent?: Record + } +} + +export * from './utils' +export * from './features' diff --git a/packages/uni-cli-shared/src/vite/utils.ts b/packages/uni-cli-shared/src/vite/utils.ts new file mode 100644 index 0000000000..8133b98391 --- /dev/null +++ b/packages/uni-cli-shared/src/vite/utils.ts @@ -0,0 +1,8 @@ +import { ResolvedConfig } from 'vite' + +// 内置组件css列表,h5平台需要合并进去首页css中 +export const buildInCssSet = new Set() + +export function isCombineBuiltInCss(config: ResolvedConfig) { + return config.command === 'build' && config.build.cssCodeSplit +} diff --git a/packages/uni-h5-vite/LICENSE b/packages/uni-h5-vite/LICENSE new file mode 100755 index 0000000000..7a4a3ea242 --- /dev/null +++ b/packages/uni-h5-vite/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/packages/uni-h5-vite/build.json b/packages/uni-h5-vite/build.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/uni-h5-vite/dist/index.js b/packages/uni-h5-vite/dist/index.js new file mode 100644 index 0000000000..083a9d263e --- /dev/null +++ b/packages/uni-h5-vite/dist/index.js @@ -0,0 +1,25 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const css_1 = require("./plugins/css"); +const cssScoped_1 = require("./plugins/cssScoped"); +const mainJs_1 = require("./plugins/mainJs"); +const manifestJson_1 = require("./plugins/manifestJson"); +const pagesJson_1 = require("./plugins/pagesJson"); +const resolveId_1 = require("./plugins/resolveId"); +const UniH5Plugin = { + name: 'vite:uni-h5', + uni: { + transformEvent: { + tap: 'click', + }, + }, +}; +exports.default = [ + cssScoped_1.uniCssScopedPlugin(), + resolveId_1.uniResolveIdPlugin(), + mainJs_1.uniMainJsPlugin(), + manifestJson_1.uniManifestJsonPlugin(), + pagesJson_1.uniPagesJsonPlugin(), + css_1.uniCssPlugin(), + UniH5Plugin, +]; diff --git a/packages/uni-h5-vite/dist/plugins/css.js b/packages/uni-h5-vite/dist/plugins/css.js new file mode 100644 index 0000000000..c8ded636c4 --- /dev/null +++ b/packages/uni-h5-vite/dist/plugins/css.js @@ -0,0 +1,45 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.uniCssPlugin = void 0; +const fs_1 = __importDefault(require("fs")); +const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared"); +function isCombineBuiltInCss(config) { + return config.command === 'build' && config.build.cssCodeSplit; +} +function uniCssPlugin() { + let resolvedConfig; + return { + name: 'vite:uni-h5-css', + apply: 'build', + enforce: 'post', + configResolved(config) { + resolvedConfig = config; + }, + generateBundle(_opts, bundle) { + // 将内置组件样式,合并进入首页 + if (!isCombineBuiltInCss(resolvedConfig) || !uni_cli_shared_1.buildInCssSet.size) { + return; + } + const chunks = Object.values(bundle); + const entryChunk = chunks.find((chunk) => chunk.type === 'chunk' && chunk.isEntry); + if (!entryChunk) { + return; + } + const entryName = entryChunk.name; + const entryCssAsset = chunks.find(({ name }) => name === entryName + '.css'); + if (entryCssAsset) { + entryCssAsset.source += + '\n' + generateBuiltInCssCode([...uni_cli_shared_1.buildInCssSet]); + } + }, + }; +} +exports.uniCssPlugin = uniCssPlugin; +function generateBuiltInCssCode(cssImports) { + return cssImports + .map((cssImport) => fs_1.default.readFileSync(uni_cli_shared_1.resolveBuiltIn(cssImport), 'utf8')) + .join('\n'); +} diff --git a/packages/uni-h5-vite/dist/plugins/cssScoped.js b/packages/uni-h5-vite/dist/plugins/cssScoped.js new file mode 100644 index 0000000000..f71eecaf54 --- /dev/null +++ b/packages/uni-h5-vite/dist/plugins/cssScoped.js @@ -0,0 +1,60 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.uniCssScopedPlugin = void 0; +const path_1 = __importDefault(require("path")); +const debug_1 = __importDefault(require("debug")); +const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared"); +const debugScoped = debug_1.default('vite:uni:scoped'); +const SCOPED_RE = /]*scoped[^>]*>/i; +function addScoped(code) { + if (SCOPED_RE.test(code)) { + return code; + } + return code.replace(/(<]*)>/gi, '$1 scoped>'); +} +function uniCssScopedPlugin() { + return { + name: 'vite:uni-h5-scoped', + enforce: 'pre', + transform(code, id) { + if (id.endsWith('App.vue')) { + return code; + } + const { filename, query } = uni_cli_shared_1.parseVueRequest(id); + if (query.vue) { + return code; + } + if (uni_cli_shared_1.EXTNAME_VUE.includes(path_1.default.extname(filename))) { + debugScoped(id); + return { + code: addScoped(code), + map: this.getCombinedSourcemap(), + }; + } + }, + handleHotUpdate(ctx) { + if (!uni_cli_shared_1.EXTNAME_VUE.includes(path_1.default.extname(ctx.file))) { + return; + } + debugScoped('hmr', ctx.file); + const oldRead = ctx.read; + ctx.read = () => __awaiter(this, void 0, void 0, function* () { + const code = yield oldRead(); + return addScoped(code); + }); + }, + }; +} +exports.uniCssScopedPlugin = uniCssScopedPlugin; diff --git a/packages/uni-h5-vite/dist/plugins/mainJs.js b/packages/uni-h5-vite/dist/plugins/mainJs.js new file mode 100644 index 0000000000..5582bb01de --- /dev/null +++ b/packages/uni-h5-vite/dist/plugins/mainJs.js @@ -0,0 +1,57 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.uniMainJsPlugin = void 0; +const path_1 = __importDefault(require("path")); +const slash_1 = __importDefault(require("slash")); +const utils_1 = require("../utils"); +function uniMainJsPlugin() { + let mainJsPath = ''; + let mainTsPath = ''; + let pagesJsonJsPath = ''; + let isSSR = false; + return { + name: 'vite:uni-h5-main-js', + enforce: 'pre', + configResolved(config) { + const mainPath = slash_1.default(path_1.default.resolve(process.env.UNI_INPUT_DIR, 'main')); + mainJsPath = mainPath + '.js'; + mainTsPath = mainPath + '.ts'; + pagesJsonJsPath = slash_1.default(path_1.default.resolve(process.env.UNI_INPUT_DIR, 'pages.json.js')); + isSSR = + utils_1.isSsr(config.command, config) || utils_1.isSsrManifest(config.command, config); + }, + transform(code, id, ssr) { + if (id === mainJsPath || id === mainTsPath) { + if (!isSSR) { + code = code.includes('createSSRApp') + ? createApp(code) + : createLegacyApp(code); + } + else { + code = ssr ? createSSRServerApp(code) : createSSRClientApp(code); + } + code = `import '${pagesJsonJsPath}';${code}`; + return { + code, + map: this.getCombinedSourcemap(), + }; + } + }, + }; +} +exports.uniMainJsPlugin = uniMainJsPlugin; +function createApp(code) { + return `import { plugin } from '@dcloudio/uni-h5';createApp().app.use(plugin).mount("#app");${code.replace('createSSRApp', 'createVueApp as createSSRApp')}`; +} +function createLegacyApp(code) { + return `import { plugin } from '@dcloudio/uni-h5';function createApp(rootComponent,rootProps){return createVueApp(rootComponent, rootProps).use(plugin)};${code.replace('createApp', 'createVueApp')}`; +} +function createSSRClientApp(code) { + return `import { plugin } from '@dcloudio/uni-h5';import { UNI_SSR, UNI_SSR_STORE } from '@dcloudio/uni-shared';const { app: __app, store: __store } = createApp();__app.use(plugin);__store && window[UNI_SSR] && window[UNI_SSR][UNI_SSR_STORE] && __store.replaceState(window[UNI_SSR][UNI_SSR_STORE]);__app.router.isReady().then(() => __app.mount("#app"));${code}`; +} +function createSSRServerApp(code) { + return code; +} diff --git a/packages/uni-h5-vite/dist/plugins/manifestJson.js b/packages/uni-h5-vite/dist/plugins/manifestJson.js new file mode 100644 index 0000000000..fa98e52e74 --- /dev/null +++ b/packages/uni-h5-vite/dist/plugins/manifestJson.js @@ -0,0 +1,87 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.uniManifestJsonPlugin = void 0; +const fs_1 = __importDefault(require("fs")); +const path_1 = __importDefault(require("path")); +const slash_1 = __importDefault(require("slash")); +const jsonc_parser_1 = require("jsonc-parser"); +const MANIFEST_JSON_JS = 'manifest.json.js'; +const defaultRouter = { + mode: 'hash', + base: '/', +}; +const defaultAsync = { + loading: 'AsyncLoading', + error: 'AsyncError', + delay: 200, + timeout: 60000, + suspensible: true, +}; +const defaultNetworkTimeout = { + request: 60000, + connectSocket: 60000, + uploadFile: 60000, + downloadFile: 60000, +}; +const defaultQQMapKey = 'XVXBZ-NDMC4-JOGUS-XGIEE-QVHDZ-AMFV2'; +function uniManifestJsonPlugin() { + let manifestJsonPath = ''; + return { + name: 'vite:uni-h5-manifest-json', + enforce: 'pre', + configResolved() { + manifestJsonPath = slash_1.default(path_1.default.join(process.env.UNI_INPUT_DIR, 'manifest.json')); + }, + resolveId(id) { + if (id.endsWith(MANIFEST_JSON_JS)) { + return manifestJsonPath + '.js'; + } + }, + transform(code, id) { + if (id.endsWith(MANIFEST_JSON_JS)) { + const manifest = JSON.parse(code); + const { debug, h5 } = manifest; + const appid = (manifest.appid || '').replace('__UNI__', ''); + const router = Object.assign(Object.assign({}, defaultRouter), ((h5 && h5.router) || {})); + if (!router.base) { + router.base = '/'; + } + const async = Object.assign(Object.assign({}, defaultAsync), ((h5 && h5.async) || {})); + const networkTimeout = Object.assign(Object.assign({}, defaultNetworkTimeout), (manifest.networkTimeout || {})); + const sdkConfigs = (h5 && h5.sdkConfigs) || {}; + const qqMapKey = (sdkConfigs.maps && + sdkConfigs.maps.qqmap && + sdkConfigs.maps.qqmap.key) || + defaultQQMapKey; + const flexDirection = (manifest['app'] && + manifest['app'].nvue && + manifest['app'].nvue['flex-direction']) || + 'column'; + return { + code: `export const appid = '${appid || ''}' +export const debug = ${!!debug} +export const nvue = ${JSON.stringify({ + 'flex-direction': flexDirection, + })} +export const networkTimeout = ${JSON.stringify(networkTimeout)} +// h5 +export const router = ${JSON.stringify(router)} +export const async = ${JSON.stringify(async)} +export const qqMapKey = '${qqMapKey}' +export const sdkConfigs = ${JSON.stringify(sdkConfigs)} +`, + map: { mappings: '' }, + }; + } + }, + load(id) { + if (id.endsWith(MANIFEST_JSON_JS)) { + return JSON.stringify(jsonc_parser_1.parse(fs_1.default.readFileSync(manifestJsonPath, 'utf8'))); + } + }, + }; +} +exports.uniManifestJsonPlugin = uniManifestJsonPlugin; diff --git a/packages/uni-h5-vite/dist/plugins/pagesJson.js b/packages/uni-h5-vite/dist/plugins/pagesJson.js new file mode 100644 index 0000000000..25d930d086 --- /dev/null +++ b/packages/uni-h5-vite/dist/plugins/pagesJson.js @@ -0,0 +1,241 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.uniPagesJsonPlugin = void 0; +const fs_1 = __importDefault(require("fs")); +const path_1 = __importDefault(require("path")); +const slash_1 = __importDefault(require("slash")); +const shared_1 = require("@vue/shared"); +const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared"); +const pkg = require('@dcloudio/vite-plugin-uni/package.json'); +const PAGES_JSON_JS = 'pages.json.js'; +function uniPagesJsonPlugin() { + let pagesJsonPath = ''; + let resolvedConfig; + return { + name: 'vite:uni-h5-pages-json', + enforce: 'pre', + configResolved(config) { + resolvedConfig = config; + pagesJsonPath = slash_1.default(path_1.default.join(process.env.UNI_INPUT_DIR, 'pages.json')); + }, + resolveId(id) { + if (id.endsWith(PAGES_JSON_JS)) { + return pagesJsonPath + '.js'; + } + }, + transform(code, id, ssr) { + if (id.endsWith(PAGES_JSON_JS)) { + return { + code: (resolvedConfig.command === 'serve' || + (resolvedConfig.command === 'build' && ssr) + ? registerGlobalCode(resolvedConfig, ssr) + : '') + generatePagesJsonCode(ssr, code, resolvedConfig), + map: { mappings: '' }, + }; + } + }, + load(id) { + if (id.endsWith(PAGES_JSON_JS)) { + return fs_1.default.readFileSync(pagesJsonPath, 'utf8'); + } + }, + }; +} +exports.uniPagesJsonPlugin = uniPagesJsonPlugin; +function generatePagesJsonCode(ssr, jsonStr, config) { + const globalName = getGlobal(ssr); + const pagesJson = uni_cli_shared_1.normalizePagesJson(jsonStr, process.env.UNI_INPUT_DIR, process.env.UNI_PLATFORM); + const { importLayoutComponentsCode, defineLayoutComponentsCode } = generateLayoutComponentsCode(globalName, pagesJson); + const definePagesCode = generatePagesDefineCode(pagesJson, config); + const uniRoutesCode = generateRoutes(globalName, pagesJson, config); + const uniConfigCode = generateConfig(globalName, pagesJson, config); + const manifestJsonPath = slash_1.default(path_1.default.resolve(process.env.UNI_INPUT_DIR, 'manifest.json.js')); + const cssCode = generateCssCode(config); + return ` +import { defineAsyncComponent, resolveComponent, createVNode, withCtx, openBlock, createBlock } from 'vue' +import { PageComponent, AsyncLoadingComponent, AsyncErrorComponent } from '@dcloudio/uni-h5' +import { appid, debug, networkTimeout, router, async, sdkConfigs, qqMapKey, nvue } from '${manifestJsonPath}' +${importLayoutComponentsCode} +const extend = Object.assign +${cssCode} +${uniConfigCode} +${defineLayoutComponentsCode} +${definePagesCode} +${uniRoutesCode} +${config.command === 'serve' ? hmrCode : ''} +export {} +`; +} +const hmrCode = `if(import.meta.hot){ + import.meta.hot.on('invalidate', (data) => { + import.meta.hot.invalidate() + }) +}`; +function getGlobal(ssr) { + return ssr ? 'global' : 'window'; +} +function registerGlobalCode(config, ssr) { + const name = getGlobal(ssr); + const rpx2pxCode = !ssr && config.define.__UNI_FEATURE_RPX__ + ? `import {upx2px} from '@dcloudio/uni-h5' + ${name}.rpx2px = upx2px +` + : ''; + return `${rpx2pxCode} +import {uni,getCurrentPages,getApp,UniServiceJSBridge,UniViewJSBridge} from '@dcloudio/uni-h5' +${name}.getApp = getApp +${name}.getCurrentPages = getCurrentPages +${name}.uni = uni +${name}.UniViewJSBridge = UniViewJSBridge +${name}.UniServiceJSBridge = UniServiceJSBridge +`; +} +function normalizePageIdentifier(path) { + return shared_1.capitalize(shared_1.camelize(path.replace(/\//g, '-'))); +} +function generateCssCode(config) { + const define = config.define; + const cssFiles = [uni_cli_shared_1.H5_FRAMEWORK_STYLE_PATH + 'base.css']; + // if (define.__UNI_FEATURE_PAGES__) { + cssFiles.push(uni_cli_shared_1.H5_FRAMEWORK_STYLE_PATH + 'async.css'); + // } + if (define.__UNI_FEATURE_RESPONSIVE__) { + cssFiles.push(uni_cli_shared_1.H5_FRAMEWORK_STYLE_PATH + 'layout.css'); + } + if (define.__UNI_FEATURE_NAVIGATIONBAR__) { + cssFiles.push(uni_cli_shared_1.H5_FRAMEWORK_STYLE_PATH + 'pageHead.css'); + } + if (define.__UNI_FEATURE_TABBAR__) { + cssFiles.push(uni_cli_shared_1.H5_FRAMEWORK_STYLE_PATH + 'tabBar.css'); + } + if (define.__UNI_FEATURE_NVUE__) { + cssFiles.push(uni_cli_shared_1.H5_FRAMEWORK_STYLE_PATH + 'nvue.css'); + } + if (define.__UNI_FEATURE_PULL_DOWN_REFRESH__) { + cssFiles.push(uni_cli_shared_1.H5_FRAMEWORK_STYLE_PATH + 'pageRefresh.css'); + } + if (define.__UNI_FEATURE_NAVIGATIONBAR_SEARCHINPUT__) { + cssFiles.push(uni_cli_shared_1.BASE_COMPONENTS_STYLE_PATH + 'input.css'); + } + if (config.command === 'serve') { + // 开发模式,自动添加所有API相关css + Object.keys(uni_cli_shared_1.API_DEPS_CSS).forEach((name) => { + const styles = uni_cli_shared_1.API_DEPS_CSS[name]; + styles.forEach((style) => { + if (!cssFiles.includes(style)) { + cssFiles.push(style); + } + }); + }); + } + return cssFiles.map((file) => `import '${file}'`).join('\n'); +} +function generateLayoutComponentsCode(globalName, pagesJson) { + const windowNames = [ + 'topWindow', + 'leftWindow', + 'rightWindow', + ]; + let importLayoutComponentsCode = ''; + let defineLayoutComponentsCode = `${globalName}.__uniLayout = ${globalName}.__uniLayout || {}\n`; + windowNames.forEach((name) => { + const windowConfig = pagesJson[name]; + if (windowConfig && windowConfig.path) { + importLayoutComponentsCode += `import ${name} from './${windowConfig.path}'\n`; + defineLayoutComponentsCode += `${globalName}.__uniConfig.${name}.component = ${name}\n`; + } + }); + return { + importLayoutComponentsCode, + defineLayoutComponentsCode, + }; +} +function generatePageDefineCode(pageOptions) { + const pageIdent = normalizePageIdentifier(pageOptions.path); + return `const ${pageIdent}Loader = ()=>import('./${pageOptions.path}?mpType=page') +const ${pageIdent} = defineAsyncComponent(extend({loader:${pageIdent}Loader},AsyncComponentOptions))`; +} +function generatePagesDefineCode(pagesJson, _config) { + const { pages } = pagesJson; + return (`const AsyncComponentOptions = { + loadingComponent: AsyncLoadingComponent, + errorComponent: AsyncErrorComponent, + delay: async.delay, + timeout: async.timeout, + suspensible: async.suspensible +} +` + pages.map((pageOptions) => generatePageDefineCode(pageOptions)).join('\n')); +} +function normalizePagesRoute(pagesJson) { + const firstPagePath = pagesJson.pages[0].path; + const tabBarList = (pagesJson.tabBar && pagesJson.tabBar.list) || []; + return pagesJson.pages.map((pageOptions) => { + const pagePath = pageOptions.path; + const name = normalizePageIdentifier(pagePath); + const isEntry = firstPagePath === pagePath ? true : undefined; + const tabBarIndex = tabBarList.findIndex((tabBarPage) => tabBarPage.pagePath === pagePath); + const isTabBar = tabBarIndex !== -1 ? true : undefined; + const isNVue = fs_1.default.existsSync(path_1.default.join(process.env.UNI_INPUT_DIR, pagePath + '.nvue')); + let windowTop = 0; + const meta = shared_1.extend({ + route: pageOptions.path, + isNVue: isNVue ? true : undefined, + isQuit: isEntry || isTabBar ? true : undefined, + isEntry, + isTabBar, + tabBarIndex, + windowTop, + }, pageOptions.style); + return { + name, + path: pageOptions.path, + meta, + }; + }); +} +function generatePageRoute({ name, path, meta }, config) { + const { isEntry } = meta; + const alias = isEntry ? `\n alias:'/${path}',` : ''; + return `{ + path:'/${isEntry ? '' : path}',${alias} + component:{setup(){return ()=>renderPage(${name})}}, + loader: ${normalizePageIdentifier(path)}Loader, + meta: ${JSON.stringify(meta)} +}`; +} +function generatePagesRoute(pagesRouteOptions, config) { + return pagesRouteOptions.map((pageOptions) => generatePageRoute(pageOptions, config)); +} +function generateRoutes(globalName, pagesJson, config) { + return ` +function renderPage(component){ + return (openBlock(), createBlock(PageComponent, null, {page: withCtx(() => [createVNode(component, { ref: "page" }, null, 512 /* NEED_PATCH */)]), _: 1 /* STABLE */})) +} +${globalName}.__uniRoutes=[${[ + ...generatePagesRoute(normalizePagesRoute(pagesJson), config), + ].join(',')}]`; +} +function generateConfig(globalName, pagesJson, config) { + delete pagesJson.pages; + delete pagesJson.subPackages; + delete pagesJson.subpackages; + pagesJson.compilerVersion = pkg['uni-app'].compilerVersion; + return ((config.command === 'serve' + ? '' + : `${globalName}['____'+appid+'____']=true +delete ${globalName}['____'+appid+'____'] +`) + + `${globalName}.__uniConfig=extend(${JSON.stringify(pagesJson)},{ + async, + debug, + networkTimeout, + sdkConfigs, + qqMapKey, + nvue, + router +}) +`); +} diff --git a/packages/uni-h5-vite/dist/plugins/resolveId.js b/packages/uni-h5-vite/dist/plugins/resolveId.js new file mode 100644 index 0000000000..55e38c3721 --- /dev/null +++ b/packages/uni-h5-vite/dist/plugins/resolveId.js @@ -0,0 +1,37 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.uniResolveIdPlugin = void 0; +const path_1 = __importDefault(require("path")); +const debug_1 = __importDefault(require("debug")); +const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared"); +const debugResolve = debug_1.default('vite:uni:resolve'); +function uniResolveIdPlugin() { + const resolveCache = {}; + return { + name: 'vite:uni-h5-resolve-id', + enforce: 'pre', + configResolved() { + const { MODE } = uni_cli_shared_1.parseCompatConfigOnce(process.env.UNI_INPUT_DIR); + resolveCache['@dcloudio/uni-h5'] = uni_cli_shared_1.resolveBuiltIn(path_1.default.join('@dcloudio/uni-h5', 'dist/uni-h5.es.js')); + resolveCache['@dcloudio/uni-h5-vue'] = uni_cli_shared_1.resolveBuiltIn(path_1.default.join('@dcloudio/uni-h5-vue', `dist/vue.runtime.${MODE === 2 ? 'compat.' : ''}esm.js`)); + }, + resolveId(id) { + if (id === 'vue') { + id = '@dcloudio/uni-h5-vue'; + } + const cache = resolveCache[id]; + if (cache) { + debugResolve('cache', id, cache); + return cache; + } + if (id.startsWith('@dcloudio/uni-h5/style') || + id.startsWith('@dcloudio/uni-components/style')) { + return (resolveCache[id] = uni_cli_shared_1.resolveBuiltIn(id)); + } + }, + }; +} +exports.uniResolveIdPlugin = uniResolveIdPlugin; diff --git a/packages/uni-h5-vite/dist/utils/index.js b/packages/uni-h5-vite/dist/utils/index.js new file mode 100644 index 0000000000..2e6e9d2a25 --- /dev/null +++ b/packages/uni-h5-vite/dist/utils/index.js @@ -0,0 +1,13 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +__exportStar(require("./ssr"), exports); diff --git a/packages/uni-h5-vite/dist/utils/ssr.js b/packages/uni-h5-vite/dist/utils/ssr.js new file mode 100644 index 0000000000..9737beff4e --- /dev/null +++ b/packages/uni-h5-vite/dist/utils/ssr.js @@ -0,0 +1,120 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.rewriteSsrRenderStyle = exports.rewriteSsrNativeTag = exports.rewriteSsrResolve = exports.rewriteSsrVue = exports.generateSsrEntryServerCode = exports.generateSsrDefineCode = exports.initSsrDefine = exports.isSsrManifest = exports.isSsr = void 0; +const path_1 = __importDefault(require("path")); +const fs_extra_1 = __importDefault(require("fs-extra")); +const shared_1 = require("@vue/shared"); +const uni_shared_1 = require("@dcloudio/uni-shared"); +const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared"); +function isSsr(command, config) { + if (command === 'serve') { + return !!(config.server && config.server.middlewareMode); + } + if (command === 'build') { + return !!(config.build && config.build.ssr); + } + return false; +} +exports.isSsr = isSsr; +function isSsrManifest(command, config) { + if (command === 'build') { + return !!(config.build && config.build.ssrManifest); + } + return false; +} +exports.isSsrManifest = isSsrManifest; +function initSsrDefine(config) { + return shared_1.extend(globalThis, { + __IMPORT_META_ENV_BASE_URL__: config.env.BASE_URL, + }); +} +exports.initSsrDefine = initSsrDefine; +function serializeDefine(define) { + let res = `{`; + for (const key in define) { + const val = define[key]; + res += `${JSON.stringify(key)}: ${typeof val === 'string' ? `(${val})` : JSON.stringify(val)}, `; + } + return res + `}`; +} +function normalizeSsrDefine(config) { + const defines = shared_1.extend({ + __IMPORT_META_ENV_BASE_URL__: JSON.stringify(config.env.BASE_URL), + }, config.define); + delete defines['import.meta.env.LEGACY']; + return defines; +} +function generateSsrDefineCode(config, { unit, unitRatio, unitPrecision }) { + return fs_extra_1.default + .readFileSync(path_1.default.join(__dirname, '../../lib/ssr/define.js'), 'utf8') + .replace('__DEFINES__', serializeDefine(normalizeSsrDefine(config))) + .replace('__UNIT__', JSON.stringify(unit)) + .replace('__UNIT_RATIO__', JSON.stringify(unitRatio)) + .replace('__UNIT_PRECISION__', JSON.stringify(unitPrecision)); +} +exports.generateSsrDefineCode = generateSsrDefineCode; +function generateSsrEntryServerCode() { + return fs_extra_1.default.readFileSync(path_1.default.join(__dirname, '../../lib/ssr/entry-server.js'), 'utf8'); +} +exports.generateSsrEntryServerCode = generateSsrEntryServerCode; +function rewriteSsrVue(mode) { + // 解决 @vue/server-renderer 中引入 vue 的映射 + let vuePath; + if (mode === 2) { + vuePath = uni_cli_shared_1.resolveBuiltIn('@dcloudio/uni-h5-vue/dist/vue.runtime.compat.cjs.js'); + } + else { + vuePath = uni_cli_shared_1.resolveBuiltIn('@dcloudio/uni-h5-vue/dist/vue.runtime.cjs.js'); + } + require('module-alias').addAlias('vue', vuePath); +} +exports.rewriteSsrVue = rewriteSsrVue; +function initResolveSyncOpts(opts) { + if (!opts) { + opts = {}; + } + if (!opts.paths) { + opts.paths = []; + } + if (shared_1.isString(opts.paths)) { + opts.paths = [opts.paths]; + } + if (shared_1.isArray(opts.paths)) { + opts.paths.push(path_1.default.join(process.env.UNI_CLI_CONTEXT, 'node_modules')); + } + return opts; +} +function rewriteSsrResolve(mode) { + // 解决 ssr 时 __vite_ssr_import__("vue") 的映射 + const resolve = require('resolve'); + const oldSync = resolve.sync; + resolve.sync = (id, opts) => { + if (id === 'vue') { + return uni_cli_shared_1.resolveBuiltIn(`@dcloudio/uni-h5-vue/dist/vue.runtime.${mode === 2 ? 'compat.' : ''}cjs.js`); + } + return oldSync(id, initResolveSyncOpts(opts)); + }; +} +exports.rewriteSsrResolve = rewriteSsrResolve; +function rewriteSsrNativeTag() { + const { parserOptions } = require('@vue/compiler-dom'); + // TODO compiler-ssr时,传入的 isNativeTag 会被 @vue/compiler-dom 的 isNativeTag 覆盖 + // https://github.com/vuejs/vue-next/blob/master/packages/compiler-ssr/src/index.ts#L36 + parserOptions.isNativeTag = uni_shared_1.isNativeTag; +} +exports.rewriteSsrNativeTag = rewriteSsrNativeTag; +function rewriteSsrRenderStyle(inputDir) { + const { unit, unitRatio, unitPrecision } = uni_cli_shared_1.parseRpx2UnitOnce(inputDir); + const rpx2unit = uni_shared_1.createRpx2Unit(unit, unitRatio, unitPrecision); + const shared = require('@vue/shared'); + const oldStringifyStyle = shared.stringifyStyle; + shared.stringifyStyle = (styles) => rpx2unit(oldStringifyStyle(styles)); + const serverRender = require('@vue/server-renderer'); + const oldSsrRenderStyle = serverRender.ssrRenderStyle; + // 仅对字符串类型做转换,非字符串类型,通过 stringifyStyle 转换 + serverRender.ssrRenderStyle = (raw) => shared_1.isString(raw) ? rpx2unit(oldSsrRenderStyle(raw)) : oldSsrRenderStyle(raw); +} +exports.rewriteSsrRenderStyle = rewriteSsrRenderStyle; diff --git a/packages/uni-h5-vite/package.json b/packages/uni-h5-vite/package.json new file mode 100644 index 0000000000..f410ffde29 --- /dev/null +++ b/packages/uni-h5-vite/package.json @@ -0,0 +1,28 @@ +{ + "name": "@dcloudio/uni-h5-vite", + "version": "3.0.0-alpha-3000020210528002", + "description": "uni-h5-vite", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "files": [ + "dist/**/*.js", + "dist/**/*.d.ts" + ], + "buildOptions": { + "bundler": "tsc" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/dcloudio/uni-app.git", + "directory": "packages/uni-h5-vite" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "uni-app": { + "name": "uni-h5", + "apply": "h5", + "main": "dist/index.js" + }, + "license": "Apache-2.0" +} diff --git a/packages/uni-h5-vite/src/index.ts b/packages/uni-h5-vite/src/index.ts new file mode 100644 index 0000000000..f69e4bbbf4 --- /dev/null +++ b/packages/uni-h5-vite/src/index.ts @@ -0,0 +1,26 @@ +import { UniVitePlugin } from '@dcloudio/uni-cli-shared' +import { uniCssPlugin } from './plugins/css' +import { uniCssScopedPlugin } from './plugins/cssScoped' +import { uniMainJsPlugin } from './plugins/mainJs' +import { uniManifestJsonPlugin } from './plugins/manifestJson' +import { uniPagesJsonPlugin } from './plugins/pagesJson' +import { uniResolveIdPlugin } from './plugins/resolveId' + +const UniH5Plugin: UniVitePlugin = { + name: 'vite:uni-h5', + uni: { + transformEvent: { + tap: 'click', + }, + }, +} + +export default [ + uniCssScopedPlugin(), + uniResolveIdPlugin(), + uniMainJsPlugin(), + uniManifestJsonPlugin(), + uniPagesJsonPlugin(), + uniCssPlugin(), + UniH5Plugin, +] diff --git a/packages/vite-plugin-uni/src/configResolved/plugins/css.ts b/packages/uni-h5-vite/src/plugins/css.ts similarity index 68% rename from packages/vite-plugin-uni/src/configResolved/plugins/css.ts rename to packages/uni-h5-vite/src/plugins/css.ts index b233324d5e..0e434d6934 100644 --- a/packages/vite-plugin-uni/src/configResolved/plugins/css.ts +++ b/packages/uni-h5-vite/src/plugins/css.ts @@ -2,20 +2,24 @@ import fs from 'fs' import { OutputAsset, OutputChunk } from 'rollup' import { Plugin, ResolvedConfig } from 'vite' -import { resolveBuiltIn } from '@dcloudio/uni-cli-shared' +import { buildInCssSet, resolveBuiltIn } from '@dcloudio/uni-cli-shared' -export const buildInCssSet = new Set() - -export function isCombineBuiltInCss(config: ResolvedConfig) { +function isCombineBuiltInCss(config: ResolvedConfig) { return config.command === 'build' && config.build.cssCodeSplit } -export function uniCssPlugin(config: ResolvedConfig): Plugin { +export function uniCssPlugin(): Plugin { + let resolvedConfig: ResolvedConfig return { - name: 'vite:uni-css', + name: 'vite:uni-h5-css', apply: 'build', + enforce: 'post', + configResolved(config) { + resolvedConfig = config + }, generateBundle(_opts, bundle) { - if (!isCombineBuiltInCss(config) || !buildInCssSet.size) { + // 将内置组件样式,合并进入首页 + if (!isCombineBuiltInCss(resolvedConfig) || !buildInCssSet.size) { return } const chunks = Object.values(bundle) diff --git a/packages/vite-plugin-uni/src/configResolved/plugins/cssScoped.ts b/packages/uni-h5-vite/src/plugins/cssScoped.ts similarity index 78% rename from packages/vite-plugin-uni/src/configResolved/plugins/cssScoped.ts rename to packages/uni-h5-vite/src/plugins/cssScoped.ts index 998cbb70a1..ad1f362bf9 100644 --- a/packages/vite-plugin-uni/src/configResolved/plugins/cssScoped.ts +++ b/packages/uni-h5-vite/src/plugins/cssScoped.ts @@ -1,10 +1,8 @@ import path from 'path' import debug from 'debug' import { Plugin } from 'vite' -import { createFilter } from '@rollup/pluginutils' -import { EXTNAME_VUE, parseVueRequest } from '@dcloudio/uni-cli-shared' -import { UniPluginFilterOptions } from '.' +import { EXTNAME_VUE, parseVueRequest } from '@dcloudio/uni-cli-shared' const debugScoped = debug('vite:uni:scoped') @@ -17,12 +15,12 @@ function addScoped(code: string) { return code.replace(/(<]*)>/gi, '$1 scoped>') } -export function uniCssScopedPlugin(options: UniPluginFilterOptions): Plugin { - const filter = createFilter(options.include, options.exclude) +export function uniCssScopedPlugin(): Plugin { return { - name: 'vite:uni-scoped', + name: 'vite:uni-h5-scoped', + enforce: 'pre', transform(code, id) { - if (!filter(id)) { + if (id.endsWith('App.vue')) { return code } const { filename, query } = parseVueRequest(id) diff --git a/packages/vite-plugin-uni/src/configResolved/plugins/mainJs.ts b/packages/uni-h5-vite/src/plugins/mainJs.ts similarity index 69% rename from packages/vite-plugin-uni/src/configResolved/plugins/mainJs.ts rename to packages/uni-h5-vite/src/plugins/mainJs.ts index 6feaac2bd6..2ee9c1db58 100644 --- a/packages/vite-plugin-uni/src/configResolved/plugins/mainJs.ts +++ b/packages/uni-h5-vite/src/plugins/mainJs.ts @@ -1,21 +1,26 @@ import path from 'path' import slash from 'slash' -import { Plugin, ResolvedConfig } from 'vite' -import { VitePluginUniResolvedOptions } from '../..' -import { isSsr, isSsrManifest } from '../../utils' +import { Plugin } from 'vite' +import { isSsr, isSsrManifest } from '../utils' -export function uniMainJsPlugin( - config: ResolvedConfig, - options: VitePluginUniResolvedOptions -): Plugin { - const mainPath = slash(path.resolve(options.inputDir, 'main')) - const mainJsPath = mainPath + '.js' - const mainTsPath = mainPath + '.ts' - const pagesJsonJsPath = slash(path.resolve(options.inputDir, 'pages.json.js')) - const isSSR = - isSsr(config.command, config) || isSsrManifest(config.command, config) +export function uniMainJsPlugin(): Plugin { + let mainJsPath = '' + let mainTsPath = '' + let pagesJsonJsPath = '' + let isSSR = false return { - name: 'vite:uni-main-js', + name: 'vite:uni-h5-main-js', + enforce: 'pre', + configResolved(config) { + const mainPath = slash(path.resolve(process.env.UNI_INPUT_DIR, 'main')) + mainJsPath = mainPath + '.js' + mainTsPath = mainPath + '.ts' + pagesJsonJsPath = slash( + path.resolve(process.env.UNI_INPUT_DIR, 'pages.json.js') + ) + isSSR = + isSsr(config.command, config) || isSsrManifest(config.command, config) + }, transform(code, id, ssr) { if (id === mainJsPath || id === mainTsPath) { if (!isSSR) { diff --git a/packages/vite-plugin-uni/src/configResolved/plugins/manifestJson.ts b/packages/uni-h5-vite/src/plugins/manifestJson.ts similarity index 79% rename from packages/vite-plugin-uni/src/configResolved/plugins/manifestJson.ts rename to packages/uni-h5-vite/src/plugins/manifestJson.ts index b23289d54e..19a2f86502 100644 --- a/packages/vite-plugin-uni/src/configResolved/plugins/manifestJson.ts +++ b/packages/uni-h5-vite/src/plugins/manifestJson.ts @@ -2,10 +2,7 @@ import fs from 'fs' import path from 'path' import slash from 'slash' import { parse } from 'jsonc-parser' -import { Plugin, ResolvedConfig } from 'vite' -import { VitePluginUniResolvedOptions } from '../..' - -import { FEATURE_DEFINES } from '../../utils' +import { Plugin } from 'vite' const MANIFEST_JSON_JS = 'manifest.json.js' @@ -31,13 +28,16 @@ const defaultNetworkTimeout = { const defaultQQMapKey = 'XVXBZ-NDMC4-JOGUS-XGIEE-QVHDZ-AMFV2' -export function uniManifestJsonPlugin( - config: ResolvedConfig, - options: VitePluginUniResolvedOptions -): Plugin { - const manifestJsonPath = slash(path.join(options.inputDir, 'manifest.json')) +export function uniManifestJsonPlugin(): Plugin { + let manifestJsonPath = '' return { - name: 'vite:uni-manifest-json', + name: 'vite:uni-h5-manifest-json', + enforce: 'pre', + configResolved() { + manifestJsonPath = slash( + path.join(process.env.UNI_INPUT_DIR, 'manifest.json') + ) + }, resolveId(id) { if (id.endsWith(MANIFEST_JSON_JS)) { return manifestJsonPath + '.js' @@ -45,7 +45,6 @@ export function uniManifestJsonPlugin( }, transform(code, id) { if (id.endsWith(MANIFEST_JSON_JS)) { - const define = config.define! as FEATURE_DEFINES const manifest = JSON.parse(code) const { debug, h5 } = manifest const appid = (manifest.appid || '').replace('__UNI__', '') @@ -53,9 +52,7 @@ export function uniManifestJsonPlugin( if (!router.base) { router.base = '/' } - const async = define.__UNI_FEATURE_PAGES__ - ? { ...defaultAsync, ...((h5 && h5.async) || {}) } - : {} + const async = { ...defaultAsync, ...((h5 && h5.async) || {}) } const networkTimeout = { ...defaultNetworkTimeout, diff --git a/packages/uni-h5-vite/src/plugins/pagesJson.ts b/packages/uni-h5-vite/src/plugins/pagesJson.ts new file mode 100644 index 0000000000..601412e879 --- /dev/null +++ b/packages/uni-h5-vite/src/plugins/pagesJson.ts @@ -0,0 +1,312 @@ +import fs from 'fs' +import path from 'path' +import slash from 'slash' +import { Plugin, ResolvedConfig } from 'vite' +import { extend, camelize, capitalize } from '@vue/shared' +import { + FEATURE_DEFINES, + H5_FRAMEWORK_STYLE_PATH, + BASE_COMPONENTS_STYLE_PATH, + normalizePagesJson, + API_DEPS_CSS, +} from '@dcloudio/uni-cli-shared' + +const pkg = require('@dcloudio/vite-plugin-uni/package.json') + +const PAGES_JSON_JS = 'pages.json.js' + +export function uniPagesJsonPlugin(): Plugin { + let pagesJsonPath = '' + let resolvedConfig: ResolvedConfig + return { + name: 'vite:uni-h5-pages-json', + enforce: 'pre', + configResolved(config) { + resolvedConfig = config + pagesJsonPath = slash(path.join(process.env.UNI_INPUT_DIR, 'pages.json')) + }, + resolveId(id) { + if (id.endsWith(PAGES_JSON_JS)) { + return pagesJsonPath + '.js' + } + }, + transform(code, id, ssr) { + if (id.endsWith(PAGES_JSON_JS)) { + return { + code: + (resolvedConfig.command === 'serve' || + (resolvedConfig.command === 'build' && ssr) + ? registerGlobalCode(resolvedConfig, ssr) + : '') + generatePagesJsonCode(ssr, code, resolvedConfig), + map: { mappings: '' }, + } + } + }, + load(id) { + if (id.endsWith(PAGES_JSON_JS)) { + return fs.readFileSync(pagesJsonPath, 'utf8') + } + }, + } +} + +interface PageRouteOptions { + name: string + path: string + meta: Partial +} + +function generatePagesJsonCode( + ssr: boolean | undefined, + jsonStr: string, + config: ResolvedConfig +) { + const globalName = getGlobal(ssr) + const pagesJson = normalizePagesJson( + jsonStr, + process.env.UNI_INPUT_DIR, + process.env.UNI_PLATFORM + ) + const { importLayoutComponentsCode, defineLayoutComponentsCode } = + generateLayoutComponentsCode(globalName, pagesJson) + const definePagesCode = generatePagesDefineCode(pagesJson, config) + const uniRoutesCode = generateRoutes(globalName, pagesJson, config) + const uniConfigCode = generateConfig(globalName, pagesJson, config) + const manifestJsonPath = slash( + path.resolve(process.env.UNI_INPUT_DIR, 'manifest.json.js') + ) + const cssCode = generateCssCode(config) + + return ` +import { defineAsyncComponent, resolveComponent, createVNode, withCtx, openBlock, createBlock } from 'vue' +import { PageComponent, AsyncLoadingComponent, AsyncErrorComponent } from '@dcloudio/uni-h5' +import { appid, debug, networkTimeout, router, async, sdkConfigs, qqMapKey, nvue } from '${manifestJsonPath}' +${importLayoutComponentsCode} +const extend = Object.assign +${cssCode} +${uniConfigCode} +${defineLayoutComponentsCode} +${definePagesCode} +${uniRoutesCode} +${config.command === 'serve' ? hmrCode : ''} +export {} +` +} + +const hmrCode = `if(import.meta.hot){ + import.meta.hot.on('invalidate', (data) => { + import.meta.hot.invalidate() + }) +}` + +function getGlobal(ssr?: boolean) { + return ssr ? 'global' : 'window' +} + +function registerGlobalCode(config: ResolvedConfig, ssr?: boolean) { + const name = getGlobal(ssr) + const rpx2pxCode = + !ssr && config.define!.__UNI_FEATURE_RPX__ + ? `import {upx2px} from '@dcloudio/uni-h5' + ${name}.rpx2px = upx2px +` + : '' + return `${rpx2pxCode} +import {uni,getCurrentPages,getApp,UniServiceJSBridge,UniViewJSBridge} from '@dcloudio/uni-h5' +${name}.getApp = getApp +${name}.getCurrentPages = getCurrentPages +${name}.uni = uni +${name}.UniViewJSBridge = UniViewJSBridge +${name}.UniServiceJSBridge = UniServiceJSBridge +` +} + +function normalizePageIdentifier(path: string) { + return capitalize(camelize(path.replace(/\//g, '-'))) +} + +function generateCssCode(config: ResolvedConfig) { + const define = config.define! as FEATURE_DEFINES + const cssFiles = [H5_FRAMEWORK_STYLE_PATH + 'base.css'] + // if (define.__UNI_FEATURE_PAGES__) { + cssFiles.push(H5_FRAMEWORK_STYLE_PATH + 'async.css') + // } + if (define.__UNI_FEATURE_RESPONSIVE__) { + cssFiles.push(H5_FRAMEWORK_STYLE_PATH + 'layout.css') + } + if (define.__UNI_FEATURE_NAVIGATIONBAR__) { + cssFiles.push(H5_FRAMEWORK_STYLE_PATH + 'pageHead.css') + } + if (define.__UNI_FEATURE_TABBAR__) { + cssFiles.push(H5_FRAMEWORK_STYLE_PATH + 'tabBar.css') + } + if (define.__UNI_FEATURE_NVUE__) { + cssFiles.push(H5_FRAMEWORK_STYLE_PATH + 'nvue.css') + } + if (define.__UNI_FEATURE_PULL_DOWN_REFRESH__) { + cssFiles.push(H5_FRAMEWORK_STYLE_PATH + 'pageRefresh.css') + } + if (define.__UNI_FEATURE_NAVIGATIONBAR_SEARCHINPUT__) { + cssFiles.push(BASE_COMPONENTS_STYLE_PATH + 'input.css') + } + if (config.command === 'serve') { + // 开发模式,自动添加所有API相关css + Object.keys(API_DEPS_CSS).forEach((name) => { + const styles = API_DEPS_CSS[name as keyof typeof API_DEPS_CSS] + styles.forEach((style) => { + if (!cssFiles.includes(style)) { + cssFiles.push(style) + } + }) + }) + } + return cssFiles.map((file) => `import '${file}'`).join('\n') +} + +function generateLayoutComponentsCode( + globalName: string, + pagesJson: UniApp.PagesJson +) { + const windowNames: Array<'topWindow' | 'leftWindow' | 'rightWindow'> = [ + 'topWindow', + 'leftWindow', + 'rightWindow', + ] + let importLayoutComponentsCode = '' + let defineLayoutComponentsCode = `${globalName}.__uniLayout = ${globalName}.__uniLayout || {}\n` + windowNames.forEach((name) => { + const windowConfig = pagesJson[name] + if (windowConfig && windowConfig.path) { + importLayoutComponentsCode += `import ${name} from './${windowConfig.path}'\n` + defineLayoutComponentsCode += `${globalName}.__uniConfig.${name}.component = ${name}\n` + } + }) + + return { + importLayoutComponentsCode, + defineLayoutComponentsCode, + } +} + +function generatePageDefineCode(pageOptions: UniApp.PagesJsonPageOptions) { + const pageIdent = normalizePageIdentifier(pageOptions.path) + return `const ${pageIdent}Loader = ()=>import('./${pageOptions.path}?mpType=page') +const ${pageIdent} = defineAsyncComponent(extend({loader:${pageIdent}Loader},AsyncComponentOptions))` +} + +function generatePagesDefineCode( + pagesJson: UniApp.PagesJson, + _config: ResolvedConfig +) { + const { pages } = pagesJson + return ( + `const AsyncComponentOptions = { + loadingComponent: AsyncLoadingComponent, + errorComponent: AsyncErrorComponent, + delay: async.delay, + timeout: async.timeout, + suspensible: async.suspensible +} +` + pages.map((pageOptions) => generatePageDefineCode(pageOptions)).join('\n') + ) +} + +function normalizePagesRoute(pagesJson: UniApp.PagesJson): PageRouteOptions[] { + const firstPagePath = pagesJson.pages[0].path + const tabBarList = (pagesJson.tabBar && pagesJson.tabBar.list) || [] + return pagesJson.pages.map((pageOptions) => { + const pagePath = pageOptions.path + const name = normalizePageIdentifier(pagePath) + const isEntry = firstPagePath === pagePath ? true : undefined + const tabBarIndex = tabBarList.findIndex( + (tabBarPage: { pagePath: string }) => tabBarPage.pagePath === pagePath + ) + const isTabBar = tabBarIndex !== -1 ? true : undefined + const isNVue = fs.existsSync( + path.join(process.env.UNI_INPUT_DIR, pagePath + '.nvue') + ) + let windowTop = 0 + const meta = extend( + { + route: pageOptions.path, + isNVue: isNVue ? true : undefined, + isQuit: isEntry || isTabBar ? true : undefined, + isEntry, + isTabBar, + tabBarIndex, + windowTop, + }, + pageOptions.style + ) + return { + name, + path: pageOptions.path, + meta, + } + }) +} + +function generatePageRoute( + { name, path, meta }: PageRouteOptions, + config: ResolvedConfig +) { + const { isEntry } = meta + const alias = isEntry ? `\n alias:'/${path}',` : '' + return `{ + path:'/${isEntry ? '' : path}',${alias} + component:{setup(){return ()=>renderPage(${name})}}, + loader: ${normalizePageIdentifier(path)}Loader, + meta: ${JSON.stringify(meta)} +}` +} + +function generatePagesRoute( + pagesRouteOptions: PageRouteOptions[], + config: ResolvedConfig +) { + return pagesRouteOptions.map((pageOptions) => + generatePageRoute(pageOptions, config) + ) +} + +function generateRoutes( + globalName: string, + pagesJson: UniApp.PagesJson, + config: ResolvedConfig +) { + return ` +function renderPage(component){ + return (openBlock(), createBlock(PageComponent, null, {page: withCtx(() => [createVNode(component, { ref: "page" }, null, 512 /* NEED_PATCH */)]), _: 1 /* STABLE */})) +} +${globalName}.__uniRoutes=[${[ + ...generatePagesRoute(normalizePagesRoute(pagesJson), config), + ].join(',')}]` +} + +function generateConfig( + globalName: string, + pagesJson: Record, + config: ResolvedConfig +) { + delete pagesJson.pages + delete pagesJson.subPackages + delete pagesJson.subpackages + pagesJson.compilerVersion = pkg['uni-app'].compilerVersion + return ( + (config.command === 'serve' + ? '' + : `${globalName}['____'+appid+'____']=true +delete ${globalName}['____'+appid+'____'] +`) + + `${globalName}.__uniConfig=extend(${JSON.stringify(pagesJson)},{ + async, + debug, + networkTimeout, + sdkConfigs, + qqMapKey, + nvue, + router +}) +` + ) +} diff --git a/packages/uni-h5-vite/src/plugins/resolveId.ts b/packages/uni-h5-vite/src/plugins/resolveId.ts new file mode 100644 index 0000000000..c8886267ec --- /dev/null +++ b/packages/uni-h5-vite/src/plugins/resolveId.ts @@ -0,0 +1,43 @@ +import path from 'path' +import debug from 'debug' +import { Plugin } from 'vite' + +import { resolveBuiltIn, parseCompatConfigOnce } from '@dcloudio/uni-cli-shared' + +const debugResolve = debug('vite:uni:resolve') + +export function uniResolveIdPlugin(): Plugin { + const resolveCache: Record = {} + return { + name: 'vite:uni-h5-resolve-id', + enforce: 'pre', + configResolved() { + const { MODE } = parseCompatConfigOnce(process.env.UNI_INPUT_DIR) + resolveCache['@dcloudio/uni-h5'] = resolveBuiltIn( + path.join('@dcloudio/uni-h5', 'dist/uni-h5.es.js') + ) + resolveCache['@dcloudio/uni-h5-vue'] = resolveBuiltIn( + path.join( + '@dcloudio/uni-h5-vue', + `dist/vue.runtime.${MODE === 2 ? 'compat.' : ''}esm.js` + ) + ) + }, + resolveId(id) { + if (id === 'vue') { + id = '@dcloudio/uni-h5-vue' + } + const cache = resolveCache[id] + if (cache) { + debugResolve('cache', id, cache) + return cache + } + if ( + id.startsWith('@dcloudio/uni-h5/style') || + id.startsWith('@dcloudio/uni-components/style') + ) { + return (resolveCache[id] = resolveBuiltIn(id)) + } + }, + } +} diff --git a/packages/uni-h5-vite/src/utils/index.ts b/packages/uni-h5-vite/src/utils/index.ts new file mode 100644 index 0000000000..1f5df197e0 --- /dev/null +++ b/packages/uni-h5-vite/src/utils/index.ts @@ -0,0 +1 @@ +export * from './ssr' diff --git a/packages/uni-h5-vite/src/utils/ssr.ts b/packages/uni-h5-vite/src/utils/ssr.ts new file mode 100644 index 0000000000..29948d2d01 --- /dev/null +++ b/packages/uni-h5-vite/src/utils/ssr.ts @@ -0,0 +1,146 @@ +import path from 'path' +import fs from 'fs-extra' +import { extend, isArray, isString, NormalizedStyle } from '@vue/shared' +import { + isNativeTag, + createRpx2Unit, + Rpx2UnitOptions, +} from '@dcloudio/uni-shared' +import { parseRpx2UnitOnce, resolveBuiltIn } from '@dcloudio/uni-cli-shared' +import { ConfigEnv, ResolvedConfig, UserConfig } from 'vite' +import resolve from 'resolve' + +export function isSsr( + command: ConfigEnv['command'], + config: UserConfig | ResolvedConfig +) { + if (command === 'serve') { + return !!(config.server && config.server.middlewareMode) + } + if (command === 'build') { + return !!(config.build && config.build.ssr) + } + return false +} + +export function isSsrManifest( + command: ConfigEnv['command'], + config: UserConfig | ResolvedConfig +) { + if (command === 'build') { + return !!(config.build && config.build.ssrManifest) + } + return false +} + +export function initSsrDefine(config: ResolvedConfig) { + return extend(globalThis, { + __IMPORT_META_ENV_BASE_URL__: config.env.BASE_URL, + }) +} + +function serializeDefine(define: Record): string { + let res = `{` + for (const key in define) { + const val = define[key] + res += `${JSON.stringify(key)}: ${ + typeof val === 'string' ? `(${val})` : JSON.stringify(val) + }, ` + } + return res + `}` +} + +function normalizeSsrDefine(config: ResolvedConfig) { + const defines = extend( + { + __IMPORT_META_ENV_BASE_URL__: JSON.stringify(config.env.BASE_URL), + }, + config.define! + ) + delete defines['import.meta.env.LEGACY'] + return defines +} +export function generateSsrDefineCode( + config: ResolvedConfig, + { unit, unitRatio, unitPrecision }: Rpx2UnitOptions +): string { + return fs + .readFileSync(path.join(__dirname, '../../lib/ssr/define.js'), 'utf8') + .replace('__DEFINES__', serializeDefine(normalizeSsrDefine(config))) + .replace('__UNIT__', JSON.stringify(unit)) + .replace('__UNIT_RATIO__', JSON.stringify(unitRatio)) + .replace('__UNIT_PRECISION__', JSON.stringify(unitPrecision)) +} + +export function generateSsrEntryServerCode() { + return fs.readFileSync( + path.join(__dirname, '../../lib/ssr/entry-server.js'), + 'utf8' + ) +} + +export function rewriteSsrVue(mode?: 2 | 3) { + // 解决 @vue/server-renderer 中引入 vue 的映射 + let vuePath: string + if (mode === 2) { + vuePath = resolveBuiltIn( + '@dcloudio/uni-h5-vue/dist/vue.runtime.compat.cjs.js' + ) + } else { + vuePath = resolveBuiltIn('@dcloudio/uni-h5-vue/dist/vue.runtime.cjs.js') + } + require('module-alias').addAlias('vue', vuePath) +} + +function initResolveSyncOpts(opts?: resolve.SyncOpts) { + if (!opts) { + opts = {} + } + if (!opts.paths) { + opts.paths = [] + } + if (isString(opts.paths)) { + opts.paths = [opts.paths] + } + if (isArray(opts.paths)) { + opts.paths.push(path.join(process.env.UNI_CLI_CONTEXT, 'node_modules')) + } + return opts +} + +export function rewriteSsrResolve(mode?: 2 | 3) { + // 解决 ssr 时 __vite_ssr_import__("vue") 的映射 + const resolve = require('resolve') + const oldSync = resolve.sync + resolve.sync = (id: string, opts?: resolve.SyncOpts) => { + if (id === 'vue') { + return resolveBuiltIn( + `@dcloudio/uni-h5-vue/dist/vue.runtime.${ + mode === 2 ? 'compat.' : '' + }cjs.js` + ) + } + return oldSync(id, initResolveSyncOpts(opts)) + } +} + +export function rewriteSsrNativeTag() { + const { parserOptions } = require('@vue/compiler-dom') + // TODO compiler-ssr时,传入的 isNativeTag 会被 @vue/compiler-dom 的 isNativeTag 覆盖 + // https://github.com/vuejs/vue-next/blob/master/packages/compiler-ssr/src/index.ts#L36 + parserOptions.isNativeTag = isNativeTag +} + +export function rewriteSsrRenderStyle(inputDir: string) { + const { unit, unitRatio, unitPrecision } = parseRpx2UnitOnce(inputDir) + const rpx2unit = createRpx2Unit(unit, unitRatio, unitPrecision) + const shared = require('@vue/shared') + const oldStringifyStyle = shared.stringifyStyle + shared.stringifyStyle = (styles: NormalizedStyle | undefined) => + rpx2unit(oldStringifyStyle(styles)) + const serverRender = require('@vue/server-renderer') + const oldSsrRenderStyle = serverRender.ssrRenderStyle + // 仅对字符串类型做转换,非字符串类型,通过 stringifyStyle 转换 + serverRender.ssrRenderStyle = (raw: unknown) => + isString(raw) ? rpx2unit(oldSsrRenderStyle(raw)) : oldSsrRenderStyle(raw) +} diff --git a/packages/uni-h5-vite/tsconfig.json b/packages/uni-h5-vite/tsconfig.json new file mode 100644 index 0000000000..7de50e34ab --- /dev/null +++ b/packages/uni-h5-vite/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.node.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": ["src", "../shims-node.d.ts", "../shims-uni-app.d.ts"] +} diff --git a/packages/uni-h5-vue/package.json b/packages/uni-h5-vue/package.json index 60014f80ef..a3ea08b3e8 100644 --- a/packages/uni-h5-vue/package.json +++ b/packages/uni-h5-vue/package.json @@ -11,7 +11,7 @@ "repository": { "type": "git", "url": "git+https://github.com/dcloudio/uni-app.git", - "directory": "packages/uni-mp-vue" + "directory": "packages/uni-h5-vue" }, "license": "Apache-2.0", "bugs": { diff --git a/packages/uni-h5/dist/uni-h5.cjs.js b/packages/uni-h5/dist/uni-h5.cjs.js index 025e199f68..9b4d7a04a7 100644 --- a/packages/uni-h5/dist/uni-h5.cjs.js +++ b/packages/uni-h5/dist/uni-h5.cjs.js @@ -6629,6 +6629,7 @@ function normalizePageMeta(pageMeta) { if (__UNI_FEATURE_NAVIGATIONBAR__) { const { navigationBar } = pageMeta; const { titleSize, titleColor, backgroundColor } = navigationBar; + navigationBar.titleText = navigationBar.titleText || ""; navigationBar.type = navigationBar.type || "default"; navigationBar.backButton = pageMeta.isQuit ? false : true; navigationBar.titleSize = titleSize || "16px"; diff --git a/packages/uni-h5/dist/uni-h5.es.js b/packages/uni-h5/dist/uni-h5.es.js index fc93fc9595..3edab1b72e 100644 --- a/packages/uni-h5/dist/uni-h5.es.js +++ b/packages/uni-h5/dist/uni-h5.es.js @@ -7020,6 +7020,7 @@ function useQuill(props2, rootRef, trigger) { let quillReady; let skipMatcher; let quill; + let textChanging = false; watch(() => props2.readOnly, (value) => { if (quillReady) { quill.enable(!value); @@ -7140,7 +7141,9 @@ function useQuill(props2, rootRef, trigger) { }); }); quill.on("text-change", () => { - trigger("input", {}, getContents()); + if (!textChanging) { + trigger("input", {}, getContents()); + } }); quill.on("selection-change", updateStatus); quill.on("scroll-optimize", () => { @@ -7243,11 +7246,13 @@ function useQuill(props2, rootRef, trigger) { const path = getRealPath(src); quill.insertEmbed(range.index, "image", path, "user"); const local = /^(file|blob):/.test(path) ? path : false; + textChanging = true; quill.formatText(range.index, 1, "data-local", local); quill.formatText(range.index, 1, "alt", alt); quill.formatText(range.index, 1, "width", width); quill.formatText(range.index, 1, "height", height); quill.formatText(range.index, 1, "class", extClass); + textChanging = false; quill.formatText(range.index, 1, "data-custom", Object.keys(data2).map((key) => `${key}=${data2[key]}`).join("&")); quill.setSelection(range.index + 1, 0, "silent"); } @@ -12987,6 +12992,7 @@ function normalizePageMeta(pageMeta) { if (__UNI_FEATURE_NAVIGATIONBAR__) { const { navigationBar } = pageMeta; const { titleSize, titleColor, backgroundColor } = navigationBar; + navigationBar.titleText = navigationBar.titleText || ""; navigationBar.type = navigationBar.type || "default"; navigationBar.backButton = pageMeta.isQuit ? false : true; navigationBar.titleSize = titleSize || "16px"; diff --git a/packages/uni-h5/lib/resolve-id.js b/packages/uni-h5/lib/resolve-id.js new file mode 100644 index 0000000000..d9f9691e99 --- /dev/null +++ b/packages/uni-h5/lib/resolve-id.js @@ -0,0 +1,28 @@ +/** + * @type {import('vite').Plugin} + */ +const UniH5ResolveIdPlugin = { + name: 'vite:uni-h5-resolve-id', + resolveId(id) { + if (id === 'vue') { + id = '@dcloudio/uni-h5-vue' + } + const cache = resolveCache[id] + if (cache) { + return cache + } + + for (const { test, resolveId } of resolvedIds) { + if (!test(id)) { + continue + } + const file = resolveId(id) + if (!file) { + continue + } + resolveCache[id] = file + debugResolve(id, file) + return file + } + }, +} diff --git a/packages/uni-h5/package.json b/packages/uni-h5/package.json index bc876da6e8..16bfb4a11b 100644 --- a/packages/uni-h5/package.json +++ b/packages/uni-h5/package.json @@ -28,9 +28,5 @@ "safe-area-insets": "^1.4.1", "xmlhttprequest": "^1.8.0" }, - "uni-app": { - "name": "uni-h5", - "apply": "h5" - }, "gitHead": "0eff378978e778420c7d2bfc9b039a387d15aac9" } diff --git a/packages/uni-h5/src/framework/setup/provide/page.ts b/packages/uni-h5/src/framework/setup/provide/page.ts index 906e429dc5..a21afde827 100644 --- a/packages/uni-h5/src/framework/setup/provide/page.ts +++ b/packages/uni-h5/src/framework/setup/provide/page.ts @@ -106,6 +106,7 @@ function normalizePageMeta(pageMeta: UniApp.PageRouteMeta) { if (__UNI_FEATURE_NAVIGATIONBAR__) { const { navigationBar } = pageMeta const { titleSize, titleColor, backgroundColor } = navigationBar + navigationBar.titleText = navigationBar.titleText || '' navigationBar.type = navigationBar.type || 'default' navigationBar.backButton = pageMeta.isQuit ? false : true navigationBar.titleSize = titleSize || '16px' diff --git a/packages/uni-shared/dist/uni-shared.cjs.js b/packages/uni-shared/dist/uni-shared.cjs.js index 6e8f10595f..37e3945e1d 100644 --- a/packages/uni-shared/dist/uni-shared.cjs.js +++ b/packages/uni-shared/dist/uni-shared.cjs.js @@ -403,6 +403,10 @@ class UniNode extends UniEventTarget { get nextSibling() { return sibling(this, 'n'); } + get nodeValue() { + return null; + } + set nodeValue(_val) { } get textContent() { return this._text || ''; } diff --git a/packages/uni-shared/dist/uni-shared.d.ts b/packages/uni-shared/dist/uni-shared.d.ts index d91bbb9cb9..e16e5f73a4 100644 --- a/packages/uni-shared/dist/uni-shared.d.ts +++ b/packages/uni-shared/dist/uni-shared.d.ts @@ -234,6 +234,8 @@ export declare class UniNode extends UniEventTarget { get firstChild(): UniNode | null; get lastChild(): UniNode | null; get nextSibling(): UniNode | null; + get nodeValue(): string | null; + set nodeValue(_val: string | null); get textContent(): string; set textContent(text: string); get parentElement(): UniElement | null; diff --git a/packages/uni-shared/dist/uni-shared.es.js b/packages/uni-shared/dist/uni-shared.es.js index b70cba7f45..21841f5882 100644 --- a/packages/uni-shared/dist/uni-shared.es.js +++ b/packages/uni-shared/dist/uni-shared.es.js @@ -399,6 +399,10 @@ class UniNode extends UniEventTarget { get nextSibling() { return sibling(this, 'n'); } + get nodeValue() { + return null; + } + set nodeValue(_val) { } get textContent() { return this._text || ''; } diff --git a/packages/uni-shared/src/vdom/Node.ts b/packages/uni-shared/src/vdom/Node.ts index a5ddff7b8b..393fccb214 100644 --- a/packages/uni-shared/src/vdom/Node.ts +++ b/packages/uni-shared/src/vdom/Node.ts @@ -47,6 +47,7 @@ export interface IUniPageNode { genId: () => number push: (...args: any[]) => void } + export class UniNode extends UniEventTarget { nodeId?: number nodeType: UniNodeType @@ -79,6 +80,12 @@ export class UniNode extends UniEventTarget { return sibling(this, 'n') } + get nodeValue() { + return null + } + + set nodeValue(_val: string | null) {} + get textContent() { return this._text || '' } diff --git a/packages/vite-plugin-uni/src/cli/index.ts b/packages/vite-plugin-uni/src/cli/index.ts index 4b424514ce..f59ecd2162 100644 --- a/packages/vite-plugin-uni/src/cli/index.ts +++ b/packages/vite-plugin-uni/src/cli/index.ts @@ -38,7 +38,7 @@ cli cli .command('') - .alias('dev') + .alias('serve') .option('--host [host]', `[string] specify hostname`) .option('--port ', `[number] specify port`) .option('--https', `[boolean] use TLS + HTTP/2`) @@ -88,7 +88,9 @@ cli .action(async (options: CliOptions & BuildOptions) => { initEnv(options) try { - await (options.ssr ? buildSSR(options) : build(options)) + await (options.ssr && options.platform === 'h5' + ? buildSSR(options) + : build(options)) } catch (e) { createLogger(options.logLevel).error( chalk.red(`error during build:\n${e.stack}`) diff --git a/packages/vite-plugin-uni/src/cli/utils.ts b/packages/vite-plugin-uni/src/cli/utils.ts index b29f70590d..8062813093 100644 --- a/packages/vite-plugin-uni/src/cli/utils.ts +++ b/packages/vite-plugin-uni/src/cli/utils.ts @@ -15,6 +15,8 @@ export const PLATFORMS = [ ] export function initEnv(options: CliOptions) { + process.env.UNI_CLI_CONTEXT = process.cwd() // TODO HBuilderX + process.env.VITE_ROOT_DIR = process.env.UNI_INPUT_DIR || process.cwd() process.env.UNI_INPUT_DIR = diff --git a/packages/vite-plugin-uni/src/configResolved/plugins/easycom.ts b/packages/vite-plugin-uni/src/configResolved/plugins/easycom.ts index c7af366643..95e3336e24 100644 --- a/packages/vite-plugin-uni/src/configResolved/plugins/easycom.ts +++ b/packages/vite-plugin-uni/src/configResolved/plugins/easycom.ts @@ -10,11 +10,12 @@ import { BASE_COMPONENTS_STYLE_PATH, COMPONENT_DEPS_CSS, parseVueRequest, + buildInCssSet, + isCombineBuiltInCss, } from '@dcloudio/uni-cli-shared' import { UniPluginFilterOptions } from '.' import { debugEasycom, matchEasycom } from '../../utils' -import { buildInCssSet, isCombineBuiltInCss } from './css' const H5_COMPONENTS_PATH = '@dcloudio/uni-h5' diff --git a/packages/vite-plugin-uni/src/configResolved/plugins/index.ts b/packages/vite-plugin-uni/src/configResolved/plugins/index.ts index 03cf457f9a..dee4523b96 100644 --- a/packages/vite-plugin-uni/src/configResolved/plugins/index.ts +++ b/packages/vite-plugin-uni/src/configResolved/plugins/index.ts @@ -4,7 +4,11 @@ import { Plugin, ResolvedConfig } from 'vite' import { FilterPattern } from '@rollup/pluginutils' import vue from '@vitejs/plugin-vue' -import { API_DEPS_CSS } from '@dcloudio/uni-cli-shared' +import { + API_DEPS_CSS, + buildInCssSet, + isCombineBuiltInCss, +} from '@dcloudio/uni-cli-shared' import { VitePluginUniResolvedOptions } from '../..' import { uniPrePlugin } from './pre' @@ -13,18 +17,13 @@ import { uniPreCssPlugin } from './preCss' import { uniEasycomPlugin } from './easycom' import { InjectOptions, uniInjectPlugin } from './inject' -import { uniMainJsPlugin } from './mainJs' -import { uniPagesJsonPlugin } from './pagesJson' -import { uniManifestJsonPlugin } from './manifestJson' import { uniPageVuePlugin } from './pageVue' import { uniCopyPlugin } from './copy' import { uniStaticPlugin } from './static' -import { uniCssScopedPlugin } from './cssScoped' import { uniRenderjsPlugin } from './renderjs' import { uniPreVuePlugin } from './preVue' import { uniSSRPlugin } from './ssr' import { uniResolveIdPlugin } from './resolveId' -import { uniCssPlugin, buildInCssSet, isCombineBuiltInCss } from './css' const debugPlugin = debug('vite:uni:plugin') @@ -49,10 +48,6 @@ const COMMON_EXCLUDE = [ const APP_VUE_RE = /App.vue$/ -const uniCssScopedPluginOptions: Partial = { - exclude: [APP_VUE_RE], -} - const uniPrePluginOptions: Partial = { exclude: [...COMMON_EXCLUDE, UNI_H5_RE], } @@ -106,24 +101,12 @@ export function initPlugins( addPlugin(plugins, uniResolveIdPlugin(options), 'vite:resolve', 'pre') - if (options.platform === 'h5') { - // h5平台需要为非App.vue组件自动增加scoped - addPlugin( - plugins, - uniCssScopedPlugin(extend(uniCssScopedPluginOptions, options)), - 0, - 'pre' - ) - } addPlugin( plugins, uniPrePlugin(extend(uniPrePluginOptions, options)), 0, 'pre' ) - addPlugin(plugins, uniMainJsPlugin(config, options), 1, 'pre') - addPlugin(plugins, uniPagesJsonPlugin(config, options), 1, 'pre') - addPlugin(plugins, uniManifestJsonPlugin(config, options), 1, 'pre') addPlugin( plugins, @@ -161,10 +144,6 @@ export function initPlugins( addPlugin(plugins, uniJsonPlugin(options), 'vite:json', 'pre') addPlugin(plugins, uniStaticPlugin(options, config), 'vite:asset', 'pre') - if (isCombineBuiltInCss(config)) { - addPlugin(plugins, uniCssPlugin(config), 'vite:asset') - } - if (command === 'build' && !config.build.ssr) { addPlugin(plugins, uniCopyPlugin(options), plugins.length) } diff --git a/packages/vite-plugin-uni/src/configResolved/plugins/resolveId.ts b/packages/vite-plugin-uni/src/configResolved/plugins/resolveId.ts index 8fc9f2bf1a..f933d28c5e 100644 --- a/packages/vite-plugin-uni/src/configResolved/plugins/resolveId.ts +++ b/packages/vite-plugin-uni/src/configResolved/plugins/resolveId.ts @@ -2,81 +2,39 @@ import path from 'path' import debug from 'debug' import { Plugin } from 'vite' -import { resolveBuiltIn, parseCompatConfigOnce } from '@dcloudio/uni-cli-shared' +import { resolveBuiltIn } from '@dcloudio/uni-cli-shared' import { VitePluginUniResolvedOptions } from '../..' -import { BuiltInModulesKey, BUILT_IN_MODULES } from '../../utils' const debugResolve = debug('vite:uni:resolve') -function getModuleType(mode?: 2 | 3) { - return mode === 2 ? 'es-compat' : 'es' +const BUILT_IN_MODULES = { + 'vue-router': 'dist/vue-router.esm-bundler.js', + vuex: 'dist/vuex.esm-bundler.js', + '@dcloudio/uni-app': 'dist/uni-app.es.js', + '@dcloudio/uni-cloud': 'dist/uni-cloud.es.js', + '@dcloudio/uni-i18n': 'dist/uni-i18n.es.js', + '@dcloudio/uni-shared': 'dist/uni-shared.es.js', } -// ssr 时,服务端 vue 的映射目前由 package.json-"vue":"npm:@dcloudio/uni-h5-vue" 处理(TODO HBuilderX) + +export type BuiltInModulesKey = keyof typeof BUILT_IN_MODULES export function uniResolveIdPlugin( - options: VitePluginUniResolvedOptions + _options: VitePluginUniResolvedOptions ): Plugin { const resolveCache: Record = {} - const resolvedIds = [ - { - test(id: string) { - return id === '@dcloudio/uni-h5-vue' - }, - resolveId(id: string) { - const files = BUILT_IN_MODULES[id as BuiltInModulesKey] - const { MODE } = parseCompatConfigOnce(options.inputDir) - return resolveBuiltIn( - path.join(id, files[getModuleType(MODE) as keyof typeof files]) - ) - }, - }, - { - test(id: string) { - return BUILT_IN_MODULES[id as BuiltInModulesKey] - }, - resolveId(id: string) { - return resolveBuiltIn( - path.join(id, BUILT_IN_MODULES[id as BuiltInModulesKey]['es']) - ) - }, - }, - { - test(id: string) { - return ( - id.startsWith('@dcloudio/uni-h5/style') || - id.startsWith('@dcloudio/uni-components/style') - ) - }, - resolveId(id: string) { - return resolveBuiltIn(id) - }, - }, - ] return { name: 'vite:uni-resolve-id', resolveId(id) { - if (id === 'vue') { - if (options.platform === 'h5') { - id = '@dcloudio/uni-h5-vue' - } - } const cache = resolveCache[id] if (cache) { + debugResolve('cache', id, cache) return cache } - - for (const { test, resolveId } of resolvedIds) { - if (!test(id)) { - continue - } - const file = resolveId(id) - if (!file) { - continue - } - resolveCache[id] = file - debugResolve(id, file) - return file + if (BUILT_IN_MODULES[id as BuiltInModulesKey]) { + return (resolveCache[id] = resolveBuiltIn( + path.join(id, BUILT_IN_MODULES[id as BuiltInModulesKey]) + )) } }, } diff --git a/packages/vite-plugin-uni/src/utils/constants.ts b/packages/vite-plugin-uni/src/utils/constants.ts deleted file mode 100644 index 01105bedb7..0000000000 --- a/packages/vite-plugin-uni/src/utils/constants.ts +++ /dev/null @@ -1,39 +0,0 @@ -// 其实应该直接通过 mainFields 来识别 -export const BUILT_IN_MODULES = { - 'vue-router': { - es: 'dist/vue-router.esm-bundler.js', - cjs: 'dist/vue-router.cjs.js', - }, - vuex: { - es: 'dist/vuex.esm-bundler.js', - cjs: 'dist/vuex.cjs.js', - }, - '@dcloudio/uni-app': { - es: 'dist/uni-app.es.js', - cjs: 'dist/uni-app.cjs.js', - }, - '@dcloudio/uni-cloud': { - es: 'dist/uni-cloud.es.js', - cjs: 'dist/uni-cloud.cjs.js', - }, - '@dcloudio/uni-h5': { - es: 'dist/uni-h5.es.js', - cjs: 'dist/uni-h5.cjs.js', - }, - '@dcloudio/uni-h5-vue': { - es: 'dist/vue.runtime.esm.js', - cjs: 'dist/vue.runtime.cjs.js', - 'es-compat': 'dist/vue.runtime.compat.esm.js', - 'cjs-compat': 'dist/vue.runtime.compat.cjs.js', - }, - '@dcloudio/uni-i18n': { - es: 'dist/uni-i18n.es.js', - cjs: 'dist/uni-i18n.cjs.js', - }, - '@dcloudio/uni-shared': { - es: 'dist/uni-shared.es.js', - cjs: 'dist/uni-shared.cjs.js', - }, -} - -export type BuiltInModulesKey = keyof typeof BUILT_IN_MODULES diff --git a/packages/vite-plugin-uni/src/utils/index.ts b/packages/vite-plugin-uni/src/utils/index.ts index e2962afe57..c16457ab2d 100644 --- a/packages/vite-plugin-uni/src/utils/index.ts +++ b/packages/vite-plugin-uni/src/utils/index.ts @@ -5,4 +5,3 @@ export * from './plugin' export * from './features' export * from './easycom' export * from './postcss' -export * from './constants' diff --git a/packages/vite-plugin-uni/src/utils/plugin.ts b/packages/vite-plugin-uni/src/utils/plugin.ts index e1e635b3d0..bf7a6c264a 100644 --- a/packages/vite-plugin-uni/src/utils/plugin.ts +++ b/packages/vite-plugin-uni/src/utils/plugin.ts @@ -23,7 +23,8 @@ function initPlugin(plugin: PluginConfig): Plugin | void { plugin.config.main || '/lib/uni.plugin.js' ) try { - return require(configFile) + const plugin = require(configFile) + return plugin.default || plugin } catch (e) { console.warn(`${configFile} not found`) } diff --git a/yarn.lock b/yarn.lock index f602979971..39f6c92406 100644 --- a/yarn.lock +++ b/yarn.lock @@ -354,6 +354,9 @@ resolved "https://registry.yarnpkg.com/@dcloudio/types/-/types-2.2.7.tgz#80d815b673e5e839c087fe252127cf79f9761eb8" integrity sha512-ipipcszcqXxG/PEIZKi5uFw4ttITpKWD0c2mwB3Bprm7p+/CEgtXYGpo6rLi8aZCc8JDgUsXMgOz79kSABAW4Q== +"@dcloudio/uni-h5-vite@./packages/uni-h5-vite": + version "3.0.0-alpha-3000020210528002" + "@eslint/eslintrc@^0.4.1": version "0.4.1" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.1.tgz#442763b88cecbe3ee0ec7ca6d6dd6168550cbf14" -- GitLab