diff --git a/.gitignore b/.gitignore index 3e8e256ad..c27dbc74a 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,12 @@ test-results /packages/vue-icon-saas/src /packages/vue-icon-saas/index.ts +/packages/vue-runtime/pc.ts +/packages/vue-runtime/mobile.ts +/packages/vue-runtime/mobile-first.ts +/packages/vue-runtime/all.ts +/packages/vue-runtime/simple.ts + /packages/react/index.ts /packages/react/pc.ts /packages/react/mobile.ts diff --git a/internals/cli/package.json b/internals/cli/package.json index 987517fb0..393caec81 100644 --- a/internals/cli/package.json +++ b/internals/cli/package.json @@ -58,6 +58,7 @@ "esno": "^0.16.3", "fast-glob": "^3.2.12", "rollup-plugin-replace": "^2.2.0", + "rollup-plugin-visualizer": "^5.12.0", "vite-plugin-dts": "~3.0.0", "vite-plugin-svgr": "^3.2.0", "vite-svg-loader": "^3.6.0" diff --git a/internals/cli/src/commands/build/build-entry-app.ts b/internals/cli/src/commands/build/build-entry-app.ts index 29245f9cb..97ff6b45a 100644 --- a/internals/cli/src/commands/build/build-entry-app.ts +++ b/internals/cli/src/commands/build/build-entry-app.ts @@ -14,7 +14,7 @@ import { getComponents, excludeComponents } from '../../shared/module-utils' import handlebarsRender from './handlebars.render' const version = getopentinyVersion({ key: 'version' }) -const outputDir = 'packages/vue' +const outputDir = 'packages/vue-runtime' const MAIN_TEMPLATE = `{{{include}}} import { $prefix } from '@opentiny/vue-common' const components = [{{{components}}}] @@ -47,25 +47,97 @@ export const install = (app, opts = {}) => { } ` -const buildFullRuntime = () => { - const outputPath = pathFromWorkspaceRoot(outputDir, 'app.ts') - const components = getComponents('all') +/** + * all 包含所有组件的所有模版 + * simple 简易模式runtime,只包含常用通用pc组件 + * pc 包含所有pc组件组件 + * mobile 包含素有mobile组件 + * mobile-first 包含所有多端组件 + */ +type RunTimeModeType = 'all' | 'pc' | 'mobile' | 'mobile-first' | 'simple' +const runtimeModeList: Array = ['all', 'pc', 'mobile', 'mobile-first', 'simple'] + +// 简易模式下需要排除的组件列表,包括chart、业务组件、冷门组件等 +const notSimpleComponents = [ + 'Amount', + 'Area', + 'AsyncFlowchart', + 'AutonaviMap', + 'BaiduMap', + 'BaseSelect', + 'BulletinBoard', + 'CascaderMobile', + 'Chart', + 'ChartBar', + 'ChartBoxplot', + 'ChartCandle', + 'ChartCore', + 'ChartFunnel', + 'ChartGauge', + 'ChartGraph', + 'ChartHeatmap', + 'ChartHistogram', + 'ChartLine', + 'ChartLiquidfill', + 'ChartMap', + 'ChartPie', + 'ChartProcess', + 'ChartRadar', + 'ChartRing', + 'ChartSankey', + 'ChartScatter', + 'ChartSunburst', + 'ChartTree', + 'ChartWaterfall', + 'ChartWordcloud', + 'Company', + 'Country', + 'Crop', + 'Currency', + 'DatePickerMobile', + 'DatePickerMobileFirst', + 'Dept', + 'DropRoles', + 'Espace', + 'Flowchart', + 'GridManager', + 'Guide', + 'Hrapprover', + 'LinkMenu', + 'Locales', + 'LogonUser', + 'Logout', + 'MindMap', + 'QrCode', + 'QueryBuilder', + 'RichText', + 'RichTextEditor', + 'River', + 'SvgIcon', + 'TextPopup', + 'ToggleMenu', + 'User', + 'UserAccount', + 'UserContact', + 'UserLink' +] + +const buildFullRuntime = (mode: RunTimeModeType) => { + const outputPath = pathFromWorkspaceRoot(outputDir, `${mode}.ts`) + const components = getComponents(mode === 'simple' ? 'pc' : mode) const includeTemplate: string[] = [] const componentsTemplate: string[] = [] - // 导出公共模块 - components.push({ - name: 'Renderless', - importName: '@opentiny/vue-renderless/common/runtime', - path: 'packages/renderless' - }) - components.forEach((item) => { - if (item.inEntry !== false && !item.path.includes('river') && !excludeComponents.includes(item.name)) { + if (item.inEntry !== false) { const component = capitalizeKebabCase(item.name) - - componentsTemplate.push(` ${component}`) - includeTemplate.push(`import ${item.name} from '${item.importName}'`) + if ( + (mode !== 'simple' && !excludeComponents.includes(item.name)) || + (mode === 'simple' && !notSimpleComponents.includes(item.name)) + ) { + componentsTemplate.push(` ${component}`) + includeTemplate.push(`import ${item.name} from '${item.importName}'`) + } } }) @@ -81,7 +153,9 @@ const buildFullRuntime = () => { fs.writeFileSync(outputPath, output) - logGreen(`npm run build:entry done. [${outputDir}/app.ts]`) + logGreen(`npm run build:entry done. [${outputDir}/${mode}.ts]`) } -buildFullRuntime() +runtimeModeList.forEach((item: RunTimeModeType) => { + buildFullRuntime(item) +}) diff --git a/internals/cli/src/commands/build/build-runtime.ts b/internals/cli/src/commands/build/build-runtime.ts index e5da79021..4c39b2f81 100644 --- a/internals/cli/src/commands/build/build-runtime.ts +++ b/internals/cli/src/commands/build/build-runtime.ts @@ -1,17 +1,17 @@ import path from 'node:path' import type { UserConfig } from 'vite' import { build } from 'vite' -import minimist from 'minimist' import commonjs from '@rollup/plugin-commonjs' import babel from '@rollup/plugin-babel' import { logGreen } from '../../shared/utils' import type { BuildUiOption, BaseConfig } from './build-ui' import { pathFromPackages, getBaseConfig, requireModules } from './build-ui' import { createProcessor } from 'tailwindcss/src/cli/build/plugin' +import { visualizer } from 'rollup-plugin-visualizer' -async function batchBuildAll({ vueVersion, tasks, message, emptyOutDir, npmScope, min }) { +async function batchBuildAll({ vueVersion, tasks, message, emptyOutDir, npmScope, min, isVisualizer }) { const rootDir = pathFromPackages('') - const runtimeDir = `dist${vueVersion}/@opentiny/vue/runtime` + const runtimeDir = `vue-runtime/dist${vueVersion}` const outDir = path.resolve(rootDir, runtimeDir) await batchBuild({ @@ -20,7 +20,8 @@ async function batchBuildAll({ vueVersion, tasks, message, emptyOutDir, npmScope message, emptyOutDir, npmScope, - min + min, + isVisualizer }) function toEntry(libs) { @@ -36,11 +37,12 @@ async function batchBuildAll({ vueVersion, tasks, message, emptyOutDir, npmScope '@vue/composition-api': 'VueCompositionAPI', '@opentiny/vue-locale': 'TinyVueLocale', '@opentiny/vue-common': 'TinyVueCommon', - '@opentiny/vue-icon': 'TinyVueIcon' + '@opentiny/vue-icon': 'TinyVueIcon', + 'echarts': 'Echarts' } } - async function batchBuild({ vueVersion, tasks, message, emptyOutDir, npmScope, min }) { + async function batchBuild({ vueVersion, tasks, message, emptyOutDir, npmScope, min, isVisualizer }) { if (tasks.length === 0) return logGreen(`====== 开始构建 ${message} ======`) @@ -72,7 +74,27 @@ async function batchBuildAll({ vueVersion, tasks, message, emptyOutDir, npmScope babel({ extensions: ['.js', '.jsx', '.mjs', '.ts', '.tsx'], presets: ['@babel/preset-env'] - }) + }), + isVisualizer + ? visualizer({ + filename: `${tasks[0].libPath}.html`, + open: true + }) + : null, + { + name: 'vite-plugin-transfer-mode', + enforce: 'pre', + transform(code, id) { + if (tasks[0].path.includes('simple') && id.includes('src/index.ts') && code.includes('pc.vue')) { + // 简易模式,手动排除移动端和多端模版 + const newCode = code.replace('mobile.vue', 'pc.vue').replace('mobile-first.vue', 'pc.vue') + return { + code: newCode, + map: null + } + } + } + } ] as any[]) ) @@ -81,7 +103,7 @@ async function batchBuildAll({ vueVersion, tasks, message, emptyOutDir, npmScope ...baseConfig, build: { emptyOutDir, - minify: min, + minify: true, sourcemap: min, rollupOptions: { external: (source, importer, isResolved) => { @@ -130,8 +152,24 @@ function getEntryTasks() { libPath: 'tiny-vue-common' }, { - path: 'vue/app.ts', - libPath: 'tiny-vue' + path: 'vue-runtime/all.ts', + libPath: 'tiny-vue-all' + }, + { + path: 'vue-runtime/simple.ts', + libPath: 'tiny-vue-simple' + }, + { + path: 'vue-runtime/pc.ts', + libPath: 'tiny-vue-pc' + }, + { + path: 'vue-runtime/mobile.ts', + libPath: 'tiny-vue-mobile' + }, + { + path: 'vue-runtime/mobile-first.ts', + libPath: 'tiny-vue-mobile-first' }, { path: 'vue-icon-saas/index.ts', @@ -149,7 +187,8 @@ export async function buildRuntime({ vueVersions = ['2', '3'], clean = false, scope = 'opentiny', - min = false + min = false, + isVisualizer = false }: BuildUiOption) { // 是否清空构建目录 let emptyOutDir = clean @@ -163,10 +202,10 @@ export async function buildRuntime({ // 这里注意不能使用多入口打包,rollup多入口打包会抽取公共依赖(再由inlineChunksPlugin插件处理),导致组件库运行时加载失败 for (let i = 0; i < tasks.length; i++) { - await batchBuildAll({ vueVersion, tasks: [tasks[i]], message, emptyOutDir, npmScope: scope, min }) + await batchBuildAll({ vueVersion, tasks: [tasks[i]], message, emptyOutDir, npmScope: scope, min, isVisualizer }) } const rootDir = pathFromPackages('') - const runtimeDir = `dist${vueVersion}/@opentiny/vue/runtime` + const runtimeDir = `vue-runtime/dist${vueVersion}` const outDir = path.resolve(rootDir, runtimeDir) const processor = await createProcessor( { diff --git a/internals/cli/src/commands/build/build-ui.ts b/internals/cli/src/commands/build/build-ui.ts index 5b33beb8d..a7774e572 100644 --- a/internals/cli/src/commands/build/build-ui.ts +++ b/internals/cli/src/commands/build/build-ui.ts @@ -373,6 +373,7 @@ export interface BuildUiOption { scope?: string // npm的组织名称 min?: boolean // 是否压缩产物 design?: string // 构建目标的设计规范 + isVisualizer?: boolean // 是否开启打包产物分析 } function getEntryTasks(): Module[] { diff --git a/internals/cli/src/index.ts b/internals/cli/src/index.ts index 8bdd5a732..25252a811 100644 --- a/internals/cli/src/index.ts +++ b/internals/cli/src/index.ts @@ -34,6 +34,7 @@ program .description('打包组件 runtime 包') .addOption(new Option('-v --vue-versions ', '目标框架,默认所有').choices(['2', '2.7', '3'])) .option('-m, --min', '是否压缩输出文件', false) + .option('-vi, --isVisualizer', '是否分析打包产物', false) .option('--tiny_mode', '输出的模板类型', 'pc') .action(buildRuntime) diff --git a/package.json b/package.json index 92bbb2a86..1797d234a 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "// ---------- 创建组件和模板打包入口 ----------": "", "create:mapping": "pnpm -C internals/cli create:mapping", "sync-icons": "pnpm -C internals/cli sync-icons", + "build:entry-app": "pnpm -C internals/cli build:entry-app", "// ---------- 打包运行时组件库 ----------": "", "build:runtime": "pnpm -C internals/cli build:runtime", "// ---------- 构建相关脚本 ----------": "", @@ -261,4 +262,4 @@ "> 1%", "last 2 versions" ] -} \ No newline at end of file +} diff --git a/packages/modules.json b/packages/modules.json index 5e3ffa6f9..76a242fb0 100644 --- a/packages/modules.json +++ b/packages/modules.json @@ -170,6 +170,25 @@ "type": "component", "exclude": false }, + "BaseSelect": { + "path": "vue/src/base-select/index.ts", + "type": "component", + "exclude": false, + "mode": [ + "mobile-first", + "pc" + ] + }, + "BaseSelectMobileFirst": { + "path": "vue/src/base-select/src/mobile-first.vue", + "type": "template", + "exclude": false + }, + "BaseSelectPc": { + "path": "vue/src/base-select/src/pc.vue", + "type": "template", + "exclude": false + }, "Breadcrumb": { "path": "vue/src/breadcrumb/index.ts", "type": "component", @@ -2329,14 +2348,6 @@ "pc" ] }, - "BaseSelect": { - "path": "vue/src/base-select/index.ts", - "type": "component", - "exclude": false, - "mode": [ - "pc" - ] - }, "SelectDropdown": { "path": "vue/src/select-dropdown/index.ts", "type": "component", diff --git a/packages/vue-runtime/package.json b/packages/vue-runtime/package.json new file mode 100644 index 000000000..59e1feaf2 --- /dev/null +++ b/packages/vue-runtime/package.json @@ -0,0 +1,18 @@ +{ + "name": "@opentiny/vue-runtime", + "version": "3.16.0", + "description": "", + "files": [ + "dist2", + "dist3" + ], + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "publishConfig": { + "access": "public" + }, + "keywords": [], + "author": "", + "license": "ISC" +}