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

feat: add uni-h5-vite

上级 fbd6a930
......@@ -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: {
......
......@@ -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)\"",
......
......@@ -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",
......
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 })],
}
......@@ -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'
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<typeof initFeatures>
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
}
import { Plugin } from 'vite'
export interface UniVitePlugin extends Plugin {
uni?: {
transformEvent?: Record<string, string>
}
}
export * from './utils'
export * from './features'
import { ResolvedConfig } from 'vite'
// 内置组件css列表,h5平台需要合并进去首页css中
export const buildInCssSet = new Set<string>()
export function isCombineBuiltInCss(config: ResolvedConfig) {
return config.command === 'build' && config.build.cssCodeSplit
}
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
"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,
];
"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');
}
"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 = /<style\s[^>]*scoped[^>]*>/i;
function addScoped(code) {
if (SCOPED_RE.test(code)) {
return code;
}
return code.replace(/(<style\b[^><]*)>/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;
"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;
}
"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;
"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
})
`);
}
"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;
"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);
"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;
{
"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"
}
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,
]
......@@ -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<string>()
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)
......
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(/(<style\b[^><]*)>/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)
......
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) {
......
......@@ -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,
......
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<UniApp.PageRouteMeta>
}
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<string, any>,
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
})
`
)
}
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<string, string> = {}
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))
}
},
}
}
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, any>): 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)
}
{
"extends": "../../tsconfig.node.json",
"compilerOptions": {
"outDir": "dist"
},
"include": ["src", "../shims-node.d.ts", "../shims-uni-app.d.ts"]
}
......@@ -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": {
......
......@@ -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";
......
......@@ -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";
......
/**
* @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
}
},
}
......@@ -28,9 +28,5 @@
"safe-area-insets": "^1.4.1",
"xmlhttprequest": "^1.8.0"
},
"uni-app": {
"name": "uni-h5",
"apply": "h5"
},
"gitHead": "0eff378978e778420c7d2bfc9b039a387d15aac9"
}
......@@ -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'
......
......@@ -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 || '';
}
......
......@@ -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;
......
......@@ -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 || '';
}
......
......@@ -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 || ''
}
......
......@@ -38,7 +38,7 @@ cli
cli
.command('')
.alias('dev')
.alias('serve')
.option('--host [host]', `[string] specify hostname`)
.option('--port <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}`)
......
......@@ -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 =
......
......@@ -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'
......
......@@ -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<UniPluginFilterOptions> = {
exclude: [APP_VUE_RE],
}
const uniPrePluginOptions: Partial<UniPluginFilterOptions> = {
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)
}
......
......@@ -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<string, string> = {}
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])
))
}
},
}
......
// 其实应该直接通过 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
......@@ -5,4 +5,3 @@ export * from './plugin'
export * from './features'
export * from './easycom'
export * from './postcss'
export * from './constants'
......@@ -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`)
}
......
......@@ -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"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册