forked from opentiny/tiny-engine
build: 公共依赖cdn解耦并增加开关控制 (#360)
* build: external public cdn localize 公共cdn依赖包支持本地化 * build: cdn外部依赖解耦,修复baseUrl获取 * build: cdn依赖解耦 修正baseUrl获取方式 * build: cdn依赖三方解耦,优化目录型拷贝 * build: cdn依赖解耦,解决目录复制文件的相对路径问题 * build(design-core): 修复monaco的worker使用cdn地址前缀的情况下打包失效 * build: 本地开发也支持脱离cdn三方依赖 * build: 去除代码注释 * build: 三方cdn依赖解耦 物料bundle文件依赖支持替换cdn依赖 * build(design-core) 去除冗余用不到的文件和配置项硬编码 * build: 公共依赖cdn解耦测试完成 开关默认关闭 * refactor: 简化三方cdn依赖解耦的正则,改为path方法 * refactor: 三方依赖解耦脚本代码优化,减少雷同的正则匹配 * refactor: 三方cdn依赖解耦脚本 简化合并正则 * build: 三方cdn解耦 物料本地打包逻辑优化修正 * build: 三方cdn依赖解耦,优化代码简化正则,修复计算版本号问题,修复函数名大小写问题 * build: 优化importMap版本站位符号 * build: 三方cdn物料解耦 变量改为环境变量 * build: 三方cdn依赖解耦 补充处理复制文件夹时候的去重 * fix: 三方cdn解耦, 解决本地启动问题 * feat(preview): preview也支持cdn依赖解耦 * refactor(desing-core/scripts): 重构复制cdn文件本地复制模块 * build: 重构预览的importMap复制逻辑,修复两个importMap文件不存在 * build: 进一步优化monacoEditor地址,直接打包不再跨网络获取 * refactor(design-core/scripts): 调整复制应用importMap函数的参数顺序,与其他结构类似 * refactor(design-core/script): 调整文件位置和文件引用顺序 * feat(design-core/preview): preview importMap.js 使用 importMap.json 数据归一 * fix(design-core/preview): 修复importJson的引用 * fix: mock端口号订正,解决element-plus拖入画布后无法渲染 * build(design-core/script): 修复临时安装包插件安装完包后返回目录不正确 * fix: 修正monaco-editor的worker资源的打包地址 * build(design-core/script): 修复临时安装包插件安装完包后返回目录不正确 * fix(design-core/preview): 修正cdn解耦preview获取动态的importMap.json的base路径问题 * build: 三方cdn解耦,优化拷贝脚本,修复文件夹当文件拷贝当文件夹是包路径时候目标路径版本号丢失 * build: 三方cdn解耦,解决包未安装的情况下,glob匹配不到文件导致打包不拷贝内容 * fix: 根据检视意见使用fs-extra readJsonSync替代utils工具函数 * fix: 根据检视意见修改函数名大小写和端口号读取 * feat: 三方物料解耦 preview变量替换增加注释 * feat: 根据检视意见修改函数名字 * refactor: 根据检视意见,将脚本函数的参数整改为对象,并把目录值迁移到参数默认值 * docs(design-core/scripts): 三方cdn解耦 修正描述错误 * fix: 三方cdn解耦 修正preview脚本TinyVue版本号
This commit is contained in:
parent
3a66996fae
commit
899d616f7e
|
@ -5,6 +5,7 @@ package-lock.json
|
||||||
yarn.lock
|
yarn.lock
|
||||||
pnpm-lock.yaml
|
pnpm-lock.yaml
|
||||||
lerna-debug.log
|
lerna-debug.log
|
||||||
|
packages/design-core/bundle-deps
|
||||||
|
|
||||||
# local env files
|
# local env files
|
||||||
.env.local
|
.env.local
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
/**
|
/**
|
||||||
* Copyright (c) 2023 - present TinyEngine Authors.
|
* Copyright (c) 2023 - present TinyEngine Authors.
|
||||||
* Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd.
|
* Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||||
*
|
*
|
||||||
* Use of this source code is governed by an MIT-style license.
|
* Use of this source code is governed by an MIT-style license.
|
||||||
*
|
*
|
||||||
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||||
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const NODE_UID = 'data-uid'
|
export const NODE_UID = 'data-uid'
|
||||||
export const NODE_TAG = 'data-tag'
|
export const NODE_TAG = 'data-tag'
|
||||||
|
@ -125,9 +125,10 @@ export const getClipboardSchema = (event) => translateStringToSchame(event.clipb
|
||||||
*/
|
*/
|
||||||
export const dynamicImportComponents = async ({ package: pkg, script, components }) => {
|
export const dynamicImportComponents = async ({ package: pkg, script, components }) => {
|
||||||
if (!script) return
|
if (!script) return
|
||||||
|
const scriptUrl = script.startsWith('.') ? new URL(script, location.href).href : script
|
||||||
|
|
||||||
if (!window.TinyComponentLibs[pkg]) {
|
if (!window.TinyComponentLibs[pkg]) {
|
||||||
const modules = await import(/* @vite-ignore */ script)
|
const modules = await import(/* @vite-ignore */ scriptUrl)
|
||||||
|
|
||||||
window.TinyComponentLibs[pkg] = modules
|
window.TinyComponentLibs[pkg] = modules
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
NODE_ENV=production
|
NODE_ENV=production
|
||||||
VITE_CDN_DOMAIN=https://npm.onmicrosoft.cn
|
VITE_CDN_DOMAIN=https://npm.onmicrosoft.cn
|
||||||
|
VITE_LOCAL_IMPORT_MAPS=false
|
||||||
|
VITE_LOCAL_BUNDLE_DEPS=false
|
||||||
# VITE_ORIGIN=
|
# VITE_ORIGIN=
|
||||||
|
|
||||||
# 错误监控上报 url
|
# 错误监控上报 url
|
||||||
|
|
|
@ -2,5 +2,7 @@
|
||||||
|
|
||||||
NODE_ENV=development
|
NODE_ENV=development
|
||||||
VITE_CDN_DOMAIN=https://npm.onmicrosoft.cn
|
VITE_CDN_DOMAIN=https://npm.onmicrosoft.cn
|
||||||
|
VITE_LOCAL_IMPORT_MAPS=false
|
||||||
|
VITE_LOCAL_BUNDLE_DEPS=false
|
||||||
# request data via alpha service
|
# request data via alpha service
|
||||||
# VITE_ORIGIN=
|
# VITE_ORIGIN=
|
||||||
|
|
|
@ -2,4 +2,6 @@
|
||||||
|
|
||||||
NODE_ENV=production
|
NODE_ENV=production
|
||||||
VITE_CDN_DOMAIN=https://npm.onmicrosoft.cn
|
VITE_CDN_DOMAIN=https://npm.onmicrosoft.cn
|
||||||
#VITE_ORIGIN=
|
VITE_LOCAL_IMPORT_MAPS=false
|
||||||
|
VITE_LOCAL_BUNDLE_DEPS=false
|
||||||
|
#VITE_ORIGIN=
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" href="/favicon.ico" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<link href="%VITE_CDN_DOMAIN%/@opentiny/vue-theme@3.14/index.css" rel="stylesheet" />
|
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
.loading-warp {
|
.loading-warp {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
@ -120,9 +120,11 @@
|
||||||
"rollup-plugin-polyfill-node": "^0.12.0",
|
"rollup-plugin-polyfill-node": "^0.12.0",
|
||||||
"rollup-plugin-terser": "^7.0.2",
|
"rollup-plugin-terser": "^7.0.2",
|
||||||
"rollup-plugin-visualizer": "^5.8.3",
|
"rollup-plugin-visualizer": "^5.8.3",
|
||||||
|
"shelljs": "^0.8.5",
|
||||||
"svg-sprite-loader": "^6.0.11",
|
"svg-sprite-loader": "^6.0.11",
|
||||||
"vite": "^4.3.7",
|
"vite": "^4.3.7",
|
||||||
"vite-plugin-monaco-editor": "^1.0.10",
|
"vite-plugin-monaco-editor": "^1.1.0",
|
||||||
|
"vite-plugin-static-copy": "^0.16.0",
|
||||||
"vite-plugin-svg-icons": "^2.0.1",
|
"vite-plugin-svg-icons": "^2.0.1",
|
||||||
"vue-eslint-parser": "^8.0.1"
|
"vue-eslint-parser": "^8.0.1"
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
import path from 'node:path'
|
||||||
|
import { readJsonSync } from 'fs-extra'
|
||||||
|
import { installPackageTemporary } from '../vite-plugins/installPackageTemporary'
|
||||||
|
import { configServerAddProxy } from '../vite-plugins/configureServerAddProxy'
|
||||||
|
import { viteStaticCopy } from 'vite-plugin-static-copy'
|
||||||
|
import {
|
||||||
|
getCdnPathNpmInfoForSingleFile,
|
||||||
|
getPackageNeedToInstallAndFilesUsingSameVersion,
|
||||||
|
dedupeCopyFiles,
|
||||||
|
copyfileToDynamicSrcMapper
|
||||||
|
} from './locateCdnNpmInfo'
|
||||||
|
|
||||||
|
export function extraBundleCdnLink(filename, originCdnPrefix) {
|
||||||
|
const result = []
|
||||||
|
const bundle = readJsonSync(filename)
|
||||||
|
bundle.data?.materials?.components?.forEach((component) => {
|
||||||
|
if (component.npm) {
|
||||||
|
const possibleUrl = [component.npm.script, component.npm.css]
|
||||||
|
possibleUrl.forEach((url) => {
|
||||||
|
if (url?.startsWith(originCdnPrefix) && !result.includes(url)) {
|
||||||
|
result.push(url)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
export function replaceBundleCdnLink(bundle, fileMap) {
|
||||||
|
bundle.data?.materials?.components?.forEach((component) => {
|
||||||
|
if (component.npm) {
|
||||||
|
const possibleUrl = ['script', 'css']
|
||||||
|
possibleUrl.forEach((key) => {
|
||||||
|
const matchRule = fileMap.find((rule) => component.npm[key] === rule.originUrl)
|
||||||
|
if (matchRule) {
|
||||||
|
component.npm[key] = matchRule.newUrl
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function copyBundleDeps({
|
||||||
|
bundleFile,
|
||||||
|
targetBundleFile,
|
||||||
|
originCdnPrefix,
|
||||||
|
base,
|
||||||
|
dir = 'material-static',
|
||||||
|
bundleTempDir = 'bundle-deps/material-static'
|
||||||
|
}) {
|
||||||
|
const cdnFiles = extraBundleCdnLink(bundleFile, originCdnPrefix).map((url) =>
|
||||||
|
getCdnPathNpmInfoForSingleFile(url, originCdnPrefix, base, dir, false, bundleTempDir)
|
||||||
|
)
|
||||||
|
const { packages: packageNeedToInstall, files } = getPackageNeedToInstallAndFilesUsingSameVersion(cdnFiles)
|
||||||
|
|
||||||
|
const plugin = (isDev) => {
|
||||||
|
return [
|
||||||
|
...(isDev ? configServerAddProxy(targetBundleFile, targetBundleFile.replace(/\.([^.]+?$)/, '-local.$1')) : []),
|
||||||
|
...installPackageTemporary(packageNeedToInstall, bundleTempDir),
|
||||||
|
...viteStaticCopy({
|
||||||
|
targets: [
|
||||||
|
...dedupeCopyFiles(files).map(copyfileToDynamicSrcMapper),
|
||||||
|
{
|
||||||
|
src: bundleFile,
|
||||||
|
dest: path.dirname(targetBundleFile),
|
||||||
|
transform: (content) => {
|
||||||
|
const json = JSON.parse(content)
|
||||||
|
replaceBundleCdnLink(json, files)
|
||||||
|
return JSON.stringify(json, null, 2)
|
||||||
|
},
|
||||||
|
rename: (filename, fileExtension) =>
|
||||||
|
isDev ? `${filename}-local.${fileExtension}` : path.basename(targetBundleFile),
|
||||||
|
overwrite: true // 覆盖public的
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
plugin
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
import { viteStaticCopy } from 'vite-plugin-static-copy'
|
||||||
|
import {
|
||||||
|
getPackageNeedToInstallAndFilesUsingSameVersion,
|
||||||
|
copyfileToDynamicSrcMapper,
|
||||||
|
dedupeCopyFiles,
|
||||||
|
getCdnPathNpmInfoForPackage,
|
||||||
|
getCdnPathNpmInfoForSingleFile
|
||||||
|
} from './locateCdnNpmInfo'
|
||||||
|
import { importmapPlugin } from '../externalDeps'
|
||||||
|
import { installPackageTemporary } from '../vite-plugins/installPackageTemporary'
|
||||||
|
|
||||||
|
export const copyLocalImportMap = ({
|
||||||
|
importMap,
|
||||||
|
styleUrls,
|
||||||
|
originCdnPrefix,
|
||||||
|
base,
|
||||||
|
dir = 'import-map-static',
|
||||||
|
bundleTempDir = 'bundle-deps/design-core-import-map',
|
||||||
|
packageCopy = [] // 值为importMap的imports的左值 (非右值的地址上的包名)
|
||||||
|
}) => {
|
||||||
|
const importMapFiles = Object.entries(importMap.imports)
|
||||||
|
.filter(([_libKey, libPath]) => libPath.startsWith(originCdnPrefix))
|
||||||
|
.map(([libKey, libPath]) => {
|
||||||
|
if (packageCopy.includes(libKey)) {
|
||||||
|
return getCdnPathNpmInfoForPackage(libPath, originCdnPrefix, base, dir, true, bundleTempDir)
|
||||||
|
}
|
||||||
|
return getCdnPathNpmInfoForSingleFile(libPath, originCdnPrefix, base, dir, false, bundleTempDir)
|
||||||
|
})
|
||||||
|
const styleFiles = styleUrls
|
||||||
|
.filter((styleUrl) => styleUrl.startsWith(originCdnPrefix))
|
||||||
|
.map((url) => getCdnPathNpmInfoForSingleFile(url, originCdnPrefix, base, dir, false), bundleTempDir)
|
||||||
|
|
||||||
|
const { packages: packageNeedToInstall, files } = getPackageNeedToInstallAndFilesUsingSameVersion(
|
||||||
|
importMapFiles.concat(styleFiles)
|
||||||
|
)
|
||||||
|
|
||||||
|
return [
|
||||||
|
...installPackageTemporary(packageNeedToInstall, bundleTempDir),
|
||||||
|
...viteStaticCopy({
|
||||||
|
targets: dedupeCopyFiles(files).map(copyfileToDynamicSrcMapper)
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
config(config, { command }) {
|
||||||
|
// 处理devAlias带CDN域名, 另外需要使得本地vue和importMap的vue是同一个实例
|
||||||
|
if (command === 'serve') {
|
||||||
|
config.resolve.alias = [
|
||||||
|
...config.resolve.alias,
|
||||||
|
{
|
||||||
|
find: /^vue$/,
|
||||||
|
replacement: `http://localhost:${config.server.port || 8080}/${
|
||||||
|
files.find(({ originUrl }) => importMap.imports.vue === originUrl).newUrl
|
||||||
|
}` // 实际端口号需要更具本地启动修改
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
importmapPlugin(
|
||||||
|
{
|
||||||
|
imports: Object.fromEntries(
|
||||||
|
Object.entries(importMap.imports).map(([k, v]) => [k, files.find((f) => f.originUrl === v)?.newUrl ?? v])
|
||||||
|
)
|
||||||
|
},
|
||||||
|
styleUrls.map((url) => styleFiles.find((f) => f.originUrl === url).newUrl ?? url)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
import path from 'node:path'
|
||||||
|
import { readJsonSync } from 'fs-extra'
|
||||||
|
import {
|
||||||
|
getPackageNeedToInstallAndFilesUsingSameVersion,
|
||||||
|
copyfileToDynamicSrcMapper,
|
||||||
|
dedupeCopyFiles,
|
||||||
|
getCdnPathNpmInfoForPackage,
|
||||||
|
getCdnPathNpmInfoForSingleFile
|
||||||
|
} from './locateCdnNpmInfo'
|
||||||
|
import { viteStaticCopy } from 'vite-plugin-static-copy'
|
||||||
|
import { installPackageTemporary } from '../vite-plugins/installPackageTemporary'
|
||||||
|
|
||||||
|
export function extraPreviewImport(filename, originCdnPrefix) {
|
||||||
|
const result = []
|
||||||
|
const importMap = readJsonSync(filename)
|
||||||
|
Object.entries(importMap.imports)?.forEach(([_key, location]) => {
|
||||||
|
const url = location.replace('${VITE_CDN_DOMAIN}', originCdnPrefix).replace('${opentinyVueVersion}', '~3.14')
|
||||||
|
if (url?.startsWith(originCdnPrefix) && !result.includes(url)) {
|
||||||
|
result.push(url)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
export function replacePreviewImport(importMap, fileMap, originCdnPrefix) {
|
||||||
|
return {
|
||||||
|
imports: Object.fromEntries(
|
||||||
|
Object.entries(importMap.imports)?.map(([key, location]) => {
|
||||||
|
// 这里的替换占位符规则等同于packages/design-core/src/preview/src/preview/importMap.js, 两边修改需要同步
|
||||||
|
const url = location.replace('${VITE_CDN_DOMAIN}', originCdnPrefix).replace('${opentinyVueVersion}', '~3.14')
|
||||||
|
const matchRule = fileMap.find((rule) => url === rule.originUrl)
|
||||||
|
if (matchRule) {
|
||||||
|
return [key, matchRule.newUrl]
|
||||||
|
}
|
||||||
|
return [key, location]
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function extraPreviewImportFile(filename, targetFileName, originCdnPrefix) {
|
||||||
|
return (fileMap) => [
|
||||||
|
{
|
||||||
|
src: filename,
|
||||||
|
dest: path.dirname(targetFileName),
|
||||||
|
transform: (content) => {
|
||||||
|
return JSON.stringify(replacePreviewImport(JSON.parse(content), fileMap, originCdnPrefix), null, 2)
|
||||||
|
},
|
||||||
|
rename: path.basename(targetFileName)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
export function copyPreviewImportMap({
|
||||||
|
importMapJson,
|
||||||
|
targetImportMapJson,
|
||||||
|
originCdnPrefix,
|
||||||
|
base,
|
||||||
|
dir = 'preview-import-map-static',
|
||||||
|
bundleTempDir = 'bundle-deps/preview-import-map',
|
||||||
|
packageCopyLib = [] // 值为cdn地址上的包名
|
||||||
|
}) {
|
||||||
|
const cdnFiles = extraPreviewImport(importMapJson, originCdnPrefix).map((url) => {
|
||||||
|
const { packageName } = url.match(
|
||||||
|
new RegExp(`^${originCdnPrefix}/?(?<packageName>.+?)@(?<versionDemand>[^/]+)(?<filePathInPackage>.*?)$`)
|
||||||
|
).groups
|
||||||
|
if (packageCopyLib.includes(packageName)) {
|
||||||
|
return getCdnPathNpmInfoForPackage(url, originCdnPrefix, base, dir, true, bundleTempDir)
|
||||||
|
}
|
||||||
|
return getCdnPathNpmInfoForSingleFile(url, originCdnPrefix, base, dir, false, bundleTempDir)
|
||||||
|
})
|
||||||
|
const { packages: packageNeedToInstall, files } = getPackageNeedToInstallAndFilesUsingSameVersion(cdnFiles)
|
||||||
|
return [
|
||||||
|
...installPackageTemporary(packageNeedToInstall, bundleTempDir),
|
||||||
|
...viteStaticCopy({
|
||||||
|
targets: [
|
||||||
|
...dedupeCopyFiles(files).map(copyfileToDynamicSrcMapper),
|
||||||
|
...extraPreviewImportFile(importMapJson, targetImportMapJson, originCdnPrefix)(files)
|
||||||
|
]
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
export * from './copyBundleDeps'
|
||||||
|
export * from './copyImportMap'
|
||||||
|
export * from './copyPreviewImportMap'
|
||||||
|
export * from './utils'
|
||||||
|
export * from './locateCdnNpmInfo'
|
||||||
|
export * from './replaceImportPath.mjs'
|
|
@ -0,0 +1,204 @@
|
||||||
|
import path from 'node:path'
|
||||||
|
import fs from 'node:fs'
|
||||||
|
import fg from 'fast-glob'
|
||||||
|
import { normalizePath } from 'vite'
|
||||||
|
import { readJsonSync } from 'fs-extra'
|
||||||
|
import { babelReplaceImportPathWithCertainFileName } from './replaceImportPath.mjs'
|
||||||
|
|
||||||
|
function transform(content, filename) {
|
||||||
|
if (filename.endsWith('.js')) {
|
||||||
|
const result = babelReplaceImportPathWithCertainFileName(content, filename, console)
|
||||||
|
return result.code || content
|
||||||
|
}
|
||||||
|
return content
|
||||||
|
}
|
||||||
|
|
||||||
|
function onlyFiles(globString) {
|
||||||
|
// viteStaticCopy 自带的glob匹配无法过滤目录, 手动过滤目录作为数组传入
|
||||||
|
return fg.sync(globString + '/**/*', { onlyFiles: true }).map((p) => normalizePath(p))
|
||||||
|
}
|
||||||
|
|
||||||
|
function replaceTailSlash(pathStr) {
|
||||||
|
// 替换尾部的 / 可以把目录当文件复制
|
||||||
|
return pathStr.replace(/\/$/, '')
|
||||||
|
}
|
||||||
|
|
||||||
|
export function copyfileToDynamicSrcMapper({ src, dest, transform, rename, folder, ...rest }) {
|
||||||
|
// viteStaticCopy 自带的glob匹配无法过滤目录, 手动过滤目录作为数组传入,但是不存在的包需要推迟glob的时机到安装文件后
|
||||||
|
return {
|
||||||
|
...rest,
|
||||||
|
get src() {
|
||||||
|
// 注意对象不能被解构,否则getter无法动态计算
|
||||||
|
return src || onlyFiles(folder)
|
||||||
|
},
|
||||||
|
dest,
|
||||||
|
transform,
|
||||||
|
rename
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成复制单个文件所需要的信息
|
||||||
|
export function getCdnPathNpmInfoForSingleFile(
|
||||||
|
url, // cdn托管的npm文件地址数组
|
||||||
|
originCdnPrefix, // cdn的前缀
|
||||||
|
base, // build构建的base(BASE_URL)参数
|
||||||
|
dir, // 复制到目标的文件目录
|
||||||
|
transformIContent = false, // 是否需要转换内容, 如果传入url实际为目录则不会转会
|
||||||
|
tempDir = 'bundle-deps' // 新安装包的安装目录
|
||||||
|
) {
|
||||||
|
const baseSlash = base.endsWith('/') ? '' : '/'
|
||||||
|
const { packageName, versionDemand, filePathInPackage } = url.match(
|
||||||
|
new RegExp(`^${originCdnPrefix}/?(?<packageName>.+?)@(?<versionDemand>[^/]+)(?<filePathInPackage>.*?)$`)
|
||||||
|
).groups
|
||||||
|
let version = versionDemand
|
||||||
|
let isFolder = filePathInPackage.endsWith('/')
|
||||||
|
let src = replaceTailSlash(`node_modules/${packageName}${filePathInPackage}`)
|
||||||
|
const sourceExist = fs.existsSync(path.resolve(src))
|
||||||
|
let sourceExistExternal = false
|
||||||
|
if (sourceExist) {
|
||||||
|
const stat = fs.statSync(path.resolve(src))
|
||||||
|
if (stat.isDirectory()) {
|
||||||
|
isFolder = true
|
||||||
|
}
|
||||||
|
const content = readJsonSync(`node_modules/${packageName}/package.json`)
|
||||||
|
version = content.version // 忽略请求的包版本,使用本地包版本号
|
||||||
|
} else {
|
||||||
|
src = tempDir + '/' + src
|
||||||
|
sourceExistExternal = fs.existsSync(path.resolve(src)) // 安装过的不重新安装, 当且仅当所有包都安装过
|
||||||
|
if (sourceExistExternal) {
|
||||||
|
const packageJson = readJsonSync(`${tempDir}/node_modules/${packageName}/package.json`)
|
||||||
|
version = packageJson.version // 如果重新安装这个版本号还需要刷新
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const updateVersion = (version) => {
|
||||||
|
const destPackageDir = `${dir}/${packageName}@${version}`
|
||||||
|
const destFullPath = `${destPackageDir}${filePathInPackage}`
|
||||||
|
const destFullPathWithoutTailSlash = replaceTailSlash(destFullPath)
|
||||||
|
const dest = path.dirname(destFullPathWithoutTailSlash)
|
||||||
|
const rename = dest.startsWith(destPackageDir) ? null : path.basename(destFullPathWithoutTailSlash) // 版本号被截断,需要补充回去
|
||||||
|
return {
|
||||||
|
version,
|
||||||
|
newUrl: `${base}${baseSlash}${destFullPath}`,
|
||||||
|
dest,
|
||||||
|
rename
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
originUrl: url,
|
||||||
|
// newUrl, // overwrite by updateVersion(version)
|
||||||
|
src,
|
||||||
|
// dest, // overwrite by updateVersion(version)
|
||||||
|
packageName,
|
||||||
|
// version, // overwrite by updateVersion(version)
|
||||||
|
versionDemand,
|
||||||
|
filePathInPackage,
|
||||||
|
sourceExist,
|
||||||
|
sourceExistExternal,
|
||||||
|
...updateVersion(version),
|
||||||
|
updateVersion,
|
||||||
|
transform: transformIContent && !isFolder ? transform : null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCdnPathNpmInfoForPackage(
|
||||||
|
url, // cdn托管的npm文件地址数组
|
||||||
|
originCdnPrefix, // cdn的前缀
|
||||||
|
base, // build构建的base(BASE_URL)参数
|
||||||
|
dir, // 复制到目标的文件目录
|
||||||
|
transformIContent = false, // 是否需要转换内容
|
||||||
|
tempDir = 'bundle-deps' // 新安装包的安装目录
|
||||||
|
) {
|
||||||
|
const baseSlash = base.endsWith('/') ? '' : '/'
|
||||||
|
const { packageName, versionDemand, filePathInPackage } = url.match(
|
||||||
|
new RegExp(`^${originCdnPrefix}/?(?<packageName>.+?)@(?<versionDemand>[^/]+)(?<filePathInPackage>.*?)$`)
|
||||||
|
).groups
|
||||||
|
let version = versionDemand
|
||||||
|
let src = `node_modules/${packageName}`
|
||||||
|
const sourceExist = fs.existsSync(path.resolve(src))
|
||||||
|
let sourceExistExternal = false
|
||||||
|
if (sourceExist) {
|
||||||
|
const content = readJsonSync(`${src}/package.json`)
|
||||||
|
version = content.version // 忽略请求的包版本,使用本地包版本号
|
||||||
|
} else {
|
||||||
|
src = tempDir + '/' + src
|
||||||
|
sourceExistExternal = fs.existsSync(path.resolve(src)) // 安装过的不重新安装, 当且仅当所有包都安装过
|
||||||
|
if (sourceExistExternal) {
|
||||||
|
const packageJson = readJsonSync(`${src}/package.json`)
|
||||||
|
version = packageJson.version // 如果重新安装这个版本号还需要刷新
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const updateVersion = (version) => {
|
||||||
|
const packageDir = `${dir}/${packageName}@${version}`
|
||||||
|
const packageDirBasename = path.basename(packageDir)
|
||||||
|
return {
|
||||||
|
version,
|
||||||
|
newUrl: `${base}${baseSlash}${dir}/${packageName}@${version}${filePathInPackage}`,
|
||||||
|
dest: path.dirname(packageDir),
|
||||||
|
rename: (_filename, _fileExtension, fullPath) => `${packageDirBasename}${fullPath.replace(src, '')}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
folder: src,
|
||||||
|
originUrl: url,
|
||||||
|
// newUrl, // overwrite by updateVersion(version)
|
||||||
|
src: sourceExist || sourceExistExternal ? onlyFiles(src) : null,
|
||||||
|
// dest, // overwrite by updateVersion(version)
|
||||||
|
packageName,
|
||||||
|
// version, // overwrite by updateVersion(version)
|
||||||
|
versionDemand,
|
||||||
|
filePathInPackage,
|
||||||
|
sourceExist,
|
||||||
|
sourceExistExternal,
|
||||||
|
...updateVersion(version),
|
||||||
|
updateVersion,
|
||||||
|
transform: transformIContent ? transform : null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function dedupeCopyFiles(files) {
|
||||||
|
return files.reduce((acc, cur) => {
|
||||||
|
//去重,分别处理字符串和数组
|
||||||
|
if (
|
||||||
|
(cur.folder && !acc.some((item) => !!item.folder && item.folder === cur.folder && item.dest === cur.dest)) || // 文件夹拷贝
|
||||||
|
(typeof cur.src === 'string' && !acc.some((item) => item.src === cur.src && item.dest === cur.dest)) // 文件拷贝
|
||||||
|
) {
|
||||||
|
acc.push(cur)
|
||||||
|
}
|
||||||
|
return acc
|
||||||
|
}, [])
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPackageNeedToInstallAndFilesUsingSameVersion(files) {
|
||||||
|
const packageNeedToInstall = files
|
||||||
|
.filter((item) => !item.sourceExist)
|
||||||
|
.map(({ packageName, version, sourceExistExternal: exist }) => ({ packageName, version, exist }))
|
||||||
|
.reduce((acc, cur) => {
|
||||||
|
// 同个包避免多个版本只保留一个版本
|
||||||
|
if (!acc.some(({ packageName }) => cur.packageName === packageName)) {
|
||||||
|
acc.push(cur)
|
||||||
|
}
|
||||||
|
return acc
|
||||||
|
}, [])
|
||||||
|
let newFiles = null
|
||||||
|
if (packageNeedToInstall.length) {
|
||||||
|
// 确保同个包多个版本只能从一个版本引用文件
|
||||||
|
newFiles = files.map((file) => {
|
||||||
|
const samePackageDifferentVersion = packageNeedToInstall.find(
|
||||||
|
({ packageName, version }) => packageName === file.packageName && version !== file.version
|
||||||
|
)
|
||||||
|
if (samePackageDifferentVersion) {
|
||||||
|
return {
|
||||||
|
...file,
|
||||||
|
...file.updateVersion(samePackageDifferentVersion.version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return file
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
packages: packageNeedToInstall,
|
||||||
|
files: newFiles ?? files
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
import fs from 'node:fs'
|
||||||
|
import path from 'node:path'
|
||||||
|
import { parse } from '@babel/core'
|
||||||
|
import traversePkg from '@babel/traverse'
|
||||||
|
import generatePkg from '@babel/generator'
|
||||||
|
const traverse = traversePkg.default
|
||||||
|
const generate = generatePkg.default
|
||||||
|
|
||||||
|
export function relativePathPattern(relativePath) {
|
||||||
|
return './' + (path.sep === '/' ? relativePath : relativePath.replace(/\\/g, '/'))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolvePath(importPath, currentFilePath) {
|
||||||
|
if (['js', 'mjs'].some(suffix =>importPath.endsWith(suffix))) { // 文件名已经带有.js,.mjs后缀
|
||||||
|
return importPath
|
||||||
|
}
|
||||||
|
const parentPath = path.resolve(currentFilePath, '../')
|
||||||
|
const filePrefix = path.resolve(parentPath, importPath)
|
||||||
|
|
||||||
|
if (fs.existsSync(filePrefix)) {
|
||||||
|
const stat = fs.statSync(filePrefix)
|
||||||
|
if (stat.isDirectory()) {
|
||||||
|
let mainFileName = 'index.js'
|
||||||
|
|
||||||
|
const packageFile = path.resolve(filePrefix, 'package.json')
|
||||||
|
|
||||||
|
if (fs.existsSync(packageFile)) {
|
||||||
|
const packageFileContent = fs.readFileSync(packageFile, { encoding: 'utf-8' })
|
||||||
|
const packageJson = JSON.parse(packageFileContent)
|
||||||
|
mainFileName = packageJson.module || packageJson.main || mainFileName
|
||||||
|
}
|
||||||
|
|
||||||
|
const mainFile = path.resolve(filePrefix, mainFileName)
|
||||||
|
if (fs.existsSync(mainFile)) {
|
||||||
|
return relativePathPattern(path.relative(parentPath, mainFile))
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return importPath
|
||||||
|
}
|
||||||
|
const possibleSuffix = ['.js', '.mjs']
|
||||||
|
const suffix = possibleSuffix.find(suf => fs.existsSync(filePrefix + suf))
|
||||||
|
if (suffix) {
|
||||||
|
return relativePathPattern(path.relative(path.resolve(currentFilePath, '../'), filePrefix + suffix))
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// babel 替换 js的相对地址引用为确定文件后缀
|
||||||
|
export function babelReplaceImportPathWithCertainFileName(content, currentFilePath, logger = console) {
|
||||||
|
let fileChangedMark = false
|
||||||
|
let result = {
|
||||||
|
code: null,
|
||||||
|
success: [],
|
||||||
|
error: []
|
||||||
|
}
|
||||||
|
const ast = parse(content, { sourceType: 'module' })
|
||||||
|
traverse(ast, {
|
||||||
|
ImportOrExportDeclaration: (astPath) => {
|
||||||
|
const node = astPath.node
|
||||||
|
if (!node.source) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const importPath = node.source.value
|
||||||
|
if(importPath.startsWith('.')) {
|
||||||
|
const certainPath = resolvePath(importPath, currentFilePath)
|
||||||
|
if(!certainPath) {
|
||||||
|
logger.warn(`File not found: ${importPath} used in ${currentFilePath}`)
|
||||||
|
result.error.push(importPath)
|
||||||
|
}
|
||||||
|
if(certainPath !== importPath) {
|
||||||
|
node.source.value = certainPath
|
||||||
|
fileChangedMark = true
|
||||||
|
result.success.push({before: importPath, after: certainPath})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (fileChangedMark) {
|
||||||
|
const { code } = generate(ast, {
|
||||||
|
jsescOption: {
|
||||||
|
quotes: 'single'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
result.code = code
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
export function getBaseUrlFromCli(fallback = '') {
|
||||||
|
// 理论上要从resolvedConfig阶段的钩子里面拿到base,由于插件嵌套插件,子插件的配置项需要在resolveConfig前传入这里,无法等resolvedConfig,故手动获取命令行base
|
||||||
|
const index = process.argv?.indexOf('--base')
|
||||||
|
return index > -1 ? process.argv[index + 1] || fallback : fallback
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
export function configServerAddProxy(path, target) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
name: 'vite-plugin-config-server-add-proxy',
|
||||||
|
configureServer(server) {
|
||||||
|
server.middlewares.use((req, _res, next) => {
|
||||||
|
if (req.url.includes(path)) {
|
||||||
|
req.url = req.url.replace(path, target)
|
||||||
|
}
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
import fs from 'node:fs'
|
||||||
|
import path from 'node:path'
|
||||||
|
import shelljs from 'shelljs'
|
||||||
|
|
||||||
|
export function installPackageTemporary(packageNeedToInstall, tempDir, logger = console) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
name: 'vite-plugin-install-package-temporary',
|
||||||
|
buildStart() {
|
||||||
|
if (packageNeedToInstall.every((pkg) => pkg.exist)) {
|
||||||
|
logger.info(`[vite-plugin-install-package-temporary]: bundle dependencies packages exist, skip install `)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let code = shelljs.mkdir('-p', tempDir).code
|
||||||
|
if (code === 0) {
|
||||||
|
//code 为 0 表示成功
|
||||||
|
fs.writeFileSync(
|
||||||
|
path.resolve(tempDir, 'package.json'),
|
||||||
|
JSON.stringify(
|
||||||
|
{
|
||||||
|
name: 'bundle-deps', // tempDir to 烤串
|
||||||
|
dependencies: Object.fromEntries(packageNeedToInstall.map((cur) => [cur.packageName, cur.version]))
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
2
|
||||||
|
),
|
||||||
|
{ encoding: 'utf-8' }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
code =
|
||||||
|
code ||
|
||||||
|
shelljs.cd(tempDir).code ||
|
||||||
|
shelljs.exec(`npm install --force`).code ||
|
||||||
|
shelljs.cd(path.relative(tempDir, '.')).code
|
||||||
|
|
||||||
|
if (code === 0) {
|
||||||
|
logger.info(
|
||||||
|
`[vite-plugin-install-package-temporary]: bundle dependencies package install success, total ${packageNeedToInstall.length} package(s)`
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
logger.warn(`[vite-plugin-install-package-temporary]: bundle dependencies package install failed`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -22,7 +22,7 @@ import { genSFCWithDefaultPlugin, parseRequiredBlocks } from '@opentiny/tiny-eng
|
||||||
import importMap from './importMap'
|
import importMap from './importMap'
|
||||||
import srcFiles from './srcFiles'
|
import srcFiles from './srcFiles'
|
||||||
import generateMetaFiles, { processAppJsCode } from './generate'
|
import generateMetaFiles, { processAppJsCode } from './generate'
|
||||||
import { getSearchParams, fetchMetaData, fetchAppSchema, fetchBlockSchema } from './http'
|
import { getSearchParams, fetchMetaData, fetchImportMap, fetchAppSchema, fetchBlockSchema } from './http'
|
||||||
import { PanelType, PreviewTips } from '../constant'
|
import { PanelType, PreviewTips } from '../constant'
|
||||||
import { injectDebugSwitch } from './debugSwitch'
|
import { injectDebugSwitch } from './debugSwitch'
|
||||||
import '@vue/repl/style.css'
|
import '@vue/repl/style.css'
|
||||||
|
@ -51,8 +51,6 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
store.setImportMap(importMap)
|
|
||||||
|
|
||||||
// 相比store.setFiles,只要少了state.activeFile = state.files[filename],因为改变activeFile会触发多余的文件解析
|
// 相比store.setFiles,只要少了state.activeFile = state.files[filename],因为改变activeFile会触发多余的文件解析
|
||||||
const setFiles = async (newFiles, mainFileName) => {
|
const setFiles = async (newFiles, mainFileName) => {
|
||||||
await store.setFiles(newFiles, mainFileName)
|
await store.setFiles(newFiles, mainFileName)
|
||||||
|
@ -61,7 +59,7 @@ export default {
|
||||||
store['initTsConfig']() // 触发获取组件d.ts方便调试
|
store['initTsConfig']() // 触发获取组件d.ts方便调试
|
||||||
}
|
}
|
||||||
|
|
||||||
const addUtilsImportMap = (utils = []) => {
|
const addUtilsImportMap = (importMap, utils = []) => {
|
||||||
const utilsImportMaps = {}
|
const utilsImportMaps = {}
|
||||||
utils.forEach(({ type, content: { package: packageName, cdnLink } }) => {
|
utils.forEach(({ type, content: { package: packageName, cdnLink } }) => {
|
||||||
if (type === 'npm' && cdnLink) {
|
if (type === 'npm' && cdnLink) {
|
||||||
|
@ -100,14 +98,27 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
const queryParams = getSearchParams()
|
const queryParams = getSearchParams()
|
||||||
|
const getImportMap = async () => {
|
||||||
|
if (import.meta.env.VITE_LOCAL_BUNDLE_DEPS === 'true') {
|
||||||
|
const mapJSON = await fetchImportMap()
|
||||||
|
return {
|
||||||
|
imports: {
|
||||||
|
...mapJSON.imports,
|
||||||
|
...getSearchParams().scripts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return importMap
|
||||||
|
}
|
||||||
|
|
||||||
const promiseList = [
|
const promiseList = [
|
||||||
fetchAppSchema(queryParams?.app),
|
fetchAppSchema(queryParams?.app),
|
||||||
fetchMetaData(queryParams),
|
fetchMetaData(queryParams),
|
||||||
setFiles(srcFiles, 'src/Main.vue')
|
setFiles(srcFiles, 'src/Main.vue'),
|
||||||
|
getImportMap()
|
||||||
]
|
]
|
||||||
Promise.all(promiseList).then(async ([appData, metaData]) => {
|
Promise.all(promiseList).then(async ([appData, metaData, _void, importMapData]) => {
|
||||||
addUtilsImportMap(metaData.utils || [])
|
addUtilsImportMap(importMapData, metaData.utils || [])
|
||||||
|
|
||||||
const blocks = await getBlocksSchema(queryParams.pageInfo?.schema)
|
const blocks = await getBlocksSchema(queryParams.pageInfo?.schema)
|
||||||
|
|
||||||
|
|
|
@ -51,5 +51,10 @@ export const fetchMetaData = async ({ platform, app, type, id, history, tenant }
|
||||||
})
|
})
|
||||||
: {}
|
: {}
|
||||||
|
|
||||||
|
export const fetchImportMap = async () => {
|
||||||
|
const baseUrl = new URL(import.meta.env.BASE_URL, location.href)
|
||||||
|
return fetch(new URL('./preview-import-map-static/preview-importmap.json', baseUrl).href).then((res) => res.json())
|
||||||
|
}
|
||||||
|
|
||||||
export const fetchAppSchema = async (id) => http.get(`/app-center/v1/api/apps/schema/${id}`)
|
export const fetchAppSchema = async (id) => http.get(`/app-center/v1/api/apps/schema/${id}`)
|
||||||
export const fetchBlockSchema = async (blockName) => http.get(`/material-center/api/block?label=${blockName}`)
|
export const fetchBlockSchema = async (blockName) => http.get(`/material-center/api/block?label=${blockName}`)
|
||||||
|
|
|
@ -13,37 +13,19 @@
|
||||||
// import { hyphenate } from '@vue/shared'
|
// import { hyphenate } from '@vue/shared'
|
||||||
|
|
||||||
import { getSearchParams } from './http'
|
import { getSearchParams } from './http'
|
||||||
|
import importMapJSON from './importMap.json'
|
||||||
import { VITE_CDN_DOMAIN } from '@opentiny/tiny-engine-controller/js/environments'
|
import { VITE_CDN_DOMAIN } from '@opentiny/tiny-engine-controller/js/environments'
|
||||||
|
|
||||||
const importMap = {}
|
const importMap = {}
|
||||||
|
|
||||||
const opentinyVueVersion = '~3.14'
|
const opentinyVueVersion = '~3.14'
|
||||||
|
|
||||||
const tinyVue3Imports = {
|
function replacePlaceholder(v) {
|
||||||
// 推荐之后统一使用@opentiny/vue去引入依赖,兼容后续录入的组件来源于tiny-vue
|
return v.replace('${VITE_CDN_DOMAIN}', VITE_CDN_DOMAIN).replace('${opentinyVueVersion}', opentinyVueVersion)
|
||||||
'@opentiny/vue': `${VITE_CDN_DOMAIN}/@opentiny/vue@${opentinyVueVersion}/runtime/tiny-vue.mjs`,
|
|
||||||
'@opentiny/vue-icon': `${VITE_CDN_DOMAIN}/@opentiny/vue@${opentinyVueVersion}/runtime/tiny-vue-icon.mjs`,
|
|
||||||
'@opentiny/vue-common': `${VITE_CDN_DOMAIN}/@opentiny/vue@${opentinyVueVersion}/runtime/tiny-vue-common.mjs`,
|
|
||||||
'@opentiny/vue-locale': `${VITE_CDN_DOMAIN}/@opentiny/vue@${opentinyVueVersion}/runtime/tiny-vue-locale.mjs`,
|
|
||||||
'@opentiny/vue-renderless/': `${VITE_CDN_DOMAIN}/@opentiny/vue-renderless@${opentinyVueVersion}/`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
importMap.imports = {
|
importMap.imports = {
|
||||||
vue: `${VITE_CDN_DOMAIN}/vue@3.2.36/dist/vue.runtime.esm-browser.js`,
|
...Object.fromEntries(Object.entries(importMapJSON.imports).map(([k, v]) => [k, replacePlaceholder(v)])),
|
||||||
'vue/server-renderer': `${VITE_CDN_DOMAIN}/@vue/server-renderer@3.2.36/dist/server-renderer.esm-browser.js`,
|
|
||||||
'vue-i18n': `${VITE_CDN_DOMAIN}/vue-i18n@9.2.0-beta.36/dist/vue-i18n.esm-browser.js`,
|
|
||||||
'vue-router': `${VITE_CDN_DOMAIN}/vue-router@4.0.16/dist/vue-router.esm-browser.js`,
|
|
||||||
'@vue/devtools-api': `${VITE_CDN_DOMAIN}/@vue/devtools-api@6.5.1/lib/esm/index.js`,
|
|
||||||
'@vueuse/core': `${VITE_CDN_DOMAIN}/@vueuse/core@9.6.0/index.mjs`,
|
|
||||||
'@vueuse/shared': `${VITE_CDN_DOMAIN}/@vueuse/shared@9.6.0/index.mjs`,
|
|
||||||
axios: `${VITE_CDN_DOMAIN}/axios@1.0.0-alpha.1/dist/esm/axios.js`,
|
|
||||||
'axios-mock-adapter': `${VITE_CDN_DOMAIN}/axios-mock-adapter@1.21.1/dist/axios-mock-adapter.js`,
|
|
||||||
'@opentiny/tiny-engine-webcomponent-core': `${VITE_CDN_DOMAIN}/@opentiny/tiny-engine-webcomponent-core@1/dist/tiny-engine-webcomponent-core.es.js`,
|
|
||||||
'@opentiny/tiny-engine-i18n-host': `${VITE_CDN_DOMAIN}/@opentiny/tiny-engine-i18n-host@1/dist/tiny-engine-i18n-host.es.js`,
|
|
||||||
'@opentiny/tiny-engine-builtin-component': `${VITE_CDN_DOMAIN}/@opentiny/tiny-engine-builtin-component@1/dist/index.js`,
|
|
||||||
'vue-demi': `${VITE_CDN_DOMAIN}/vue-demi@0.13.11/lib/index.mjs`,
|
|
||||||
pinia: `${VITE_CDN_DOMAIN}/pinia@2.0.22/dist/pinia.esm-browser.js`,
|
|
||||||
...tinyVue3Imports,
|
|
||||||
...getSearchParams().scripts
|
...getSearchParams().scripts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"imports": {
|
||||||
|
"vue": "${VITE_CDN_DOMAIN}/vue@3.4.23/dist/vue.runtime.esm-browser.js",
|
||||||
|
"vue/server-renderer": "${VITE_CDN_DOMAIN}/@vue/server-renderer@3.4.23/dist/server-renderer.esm-browser.js",
|
||||||
|
"vue-i18n": "${VITE_CDN_DOMAIN}/vue-i18n@9.2.0-beta.36/dist/vue-i18n.esm-browser.js",
|
||||||
|
"vue-router": "${VITE_CDN_DOMAIN}/vue-router@4.0.16/dist/vue-router.esm-browser.js",
|
||||||
|
"@vue/devtools-api": "${VITE_CDN_DOMAIN}/@vue/devtools-api@6.5.1/lib/esm/index.js",
|
||||||
|
"@vueuse/core": "${VITE_CDN_DOMAIN}/@vueuse/core@9.6.0/index.mjs",
|
||||||
|
"@vueuse/shared": "${VITE_CDN_DOMAIN}/@vueuse/shared@9.6.0/index.mjs",
|
||||||
|
"axios": "${VITE_CDN_DOMAIN}/axios@1.0.0/dist/esm/axios.js",
|
||||||
|
"axios-mock-adapter": "${VITE_CDN_DOMAIN}/axios-mock-adapter@1.21.1/dist/axios-mock-adapter.js",
|
||||||
|
"@opentiny/tiny-engine-webcomponent-core": "${VITE_CDN_DOMAIN}/@opentiny/tiny-engine-webcomponent-core@1/dist/tiny-engine-webcomponent-core.es.js",
|
||||||
|
"@opentiny/tiny-engine-i18n-host": "${VITE_CDN_DOMAIN}/@opentiny/tiny-engine-i18n-host@1/dist/lowcode-design-i18n-host.es.js",
|
||||||
|
"@opentiny/tiny-engine-builtin-component": "${VITE_CDN_DOMAIN}/@opentiny/tiny-engine-builtin-component@1/dist/index.js",
|
||||||
|
"vue-demi": "${VITE_CDN_DOMAIN}/vue-demi@0.13.11/lib/index.mjs",
|
||||||
|
"pinia": "${VITE_CDN_DOMAIN}/pinia@2.0.22/dist/pinia.esm-browser.js",
|
||||||
|
"@opentiny/vue": "${VITE_CDN_DOMAIN}/@opentiny/vue@${opentinyVueVersion}/runtime/tiny-vue.mjs",
|
||||||
|
"@opentiny/vue-icon": "${VITE_CDN_DOMAIN}/@opentiny/vue@${opentinyVueVersion}/runtime/tiny-vue-icon.mjs",
|
||||||
|
"@opentiny/vue-common": "${VITE_CDN_DOMAIN}/@opentiny/vue@${opentinyVueVersion}/runtime/tiny-vue-common.mjs",
|
||||||
|
"@opentiny/vue-locale": "${VITE_CDN_DOMAIN}/@opentiny/vue@${opentinyVueVersion}/runtime/tiny-vue-locale.mjs",
|
||||||
|
"@opentiny/vue-renderless/": "${VITE_CDN_DOMAIN}/@opentiny/vue-renderless@${opentinyVueVersion}/"
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,6 +12,7 @@ import lowcodeConfig from './config/lowcode.config'
|
||||||
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
|
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
|
||||||
import { importmapPlugin } from './scripts/externalDeps'
|
import { importmapPlugin } from './scripts/externalDeps'
|
||||||
import visualizer from 'rollup-plugin-visualizer'
|
import visualizer from 'rollup-plugin-visualizer'
|
||||||
|
import { getBaseUrlFromCli, copyBundleDeps, copyPreviewImportMap, copyLocalImportMap } from './scripts/localCdnFile'
|
||||||
|
|
||||||
const origin = 'http://localhost:9090/'
|
const origin = 'http://localhost:9090/'
|
||||||
|
|
||||||
|
@ -197,14 +198,16 @@ const commonAlias = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defineConfig(({ command, mode }) => {
|
export default defineConfig(({ command, mode }) => {
|
||||||
const { VITE_CDN_DOMAIN } = loadEnv(mode, process.cwd(), '')
|
const { VITE_CDN_DOMAIN, VITE_LOCAL_IMPORT_MAPS, VITE_LOCAL_BUNDLE_DEPS } = loadEnv(mode, process.cwd(), '')
|
||||||
const monacoPublicPath = {
|
const isLocalImportMap = VITE_LOCAL_IMPORT_MAPS === 'true' // true公共依赖库使用本地打包文件,false公共依赖库使用公共CDN
|
||||||
local: 'editor/monaco-workers',
|
const isCopyBundleDeps = VITE_LOCAL_BUNDLE_DEPS === 'true' // true bundle里的cdn依赖处理成本地依赖, false 不处理
|
||||||
alpha: 'https://tinyengine-assets.obs.cn-north-4.myhuaweicloud.com/files/monaco-assets',
|
|
||||||
prod: 'https://tinyengine-assets.obs.cn-north-4.myhuaweicloud.com/files/monaco-assets'
|
|
||||||
}
|
|
||||||
|
|
||||||
let monacoEditorPluginInstance = monacoEditorPlugin({ publicPath: monacoPublicPath.local })
|
const monacoPublicPath = 'editor/monaco-workers'
|
||||||
|
const monacoEditorPluginInstance = monacoEditorPlugin({
|
||||||
|
publicPath: monacoPublicPath,
|
||||||
|
forceBuildCDN: true,
|
||||||
|
customDistPath: (_root, outDir, _base) => path.join(outDir, monacoPublicPath)
|
||||||
|
})
|
||||||
const htmlPlugin = (mode) => {
|
const htmlPlugin = (mode) => {
|
||||||
const upgradeHttpsMetaTags = []
|
const upgradeHttpsMetaTags = []
|
||||||
const includeHtmls = ['index.html', 'preview.html', 'previewApp.html']
|
const includeHtmls = ['index.html', 'preview.html', 'previewApp.html']
|
||||||
|
@ -241,7 +244,7 @@ export default defineConfig(({ command, mode }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
config.resolve.alias = [
|
config.resolve.alias = [
|
||||||
devVueAlias,
|
...(isLocalImportMap ? [] : [devVueAlias]),
|
||||||
...Object.entries({ ...commonAlias, ...devAlias }).map(([find, replacement]) => ({
|
...Object.entries({ ...commonAlias, ...devAlias }).map(([find, replacement]) => ({
|
||||||
find,
|
find,
|
||||||
replacement
|
replacement
|
||||||
|
@ -251,8 +254,6 @@ export default defineConfig(({ command, mode }) => {
|
||||||
// command === 'build'
|
// command === 'build'
|
||||||
config.resolve.alias = { ...commonAlias, ...prodAlias }
|
config.resolve.alias = { ...commonAlias, ...prodAlias }
|
||||||
|
|
||||||
monacoEditorPluginInstance = monacoEditorPlugin({ publicPath: monacoPublicPath[mode] })
|
|
||||||
|
|
||||||
if (mode === 'prod') {
|
if (mode === 'prod') {
|
||||||
config.build.minify = true
|
config.build.minify = true
|
||||||
config.build.sourcemap = false
|
config.build.sourcemap = false
|
||||||
|
@ -276,14 +277,49 @@ export default defineConfig(({ command, mode }) => {
|
||||||
'@opentiny/vue-common': `${VITE_CDN_DOMAIN}/@opentiny/vue@${importMapVersions.tinyVue}/runtime/tiny-vue-common.mjs`,
|
'@opentiny/vue-common': `${VITE_CDN_DOMAIN}/@opentiny/vue@${importMapVersions.tinyVue}/runtime/tiny-vue-common.mjs`,
|
||||||
'@opentiny/vue-locale': `${VITE_CDN_DOMAIN}/@opentiny/vue@${importMapVersions.tinyVue}/runtime/tiny-vue-locale.mjs`,
|
'@opentiny/vue-locale': `${VITE_CDN_DOMAIN}/@opentiny/vue@${importMapVersions.tinyVue}/runtime/tiny-vue-locale.mjs`,
|
||||||
'@opentiny/vue-design-smb': `${VITE_CDN_DOMAIN}/@opentiny/vue-design-smb@${importMapVersions.tinyVue}/index.js`,
|
'@opentiny/vue-design-smb': `${VITE_CDN_DOMAIN}/@opentiny/vue-design-smb@${importMapVersions.tinyVue}/index.js`,
|
||||||
'@opentiny/vue-theme/theme-tool': `${VITE_CDN_DOMAIN}/@opentiny/vue-theme@${importMapVersions.tinyVue}/theme-tool`,
|
'@opentiny/vue-theme/theme-tool': `${VITE_CDN_DOMAIN}/@opentiny/vue-theme@${importMapVersions.tinyVue}/theme-tool.js`,
|
||||||
'@opentiny/vue-theme/theme': `${VITE_CDN_DOMAIN}/@opentiny/vue-theme@${importMapVersions.tinyVue}/theme`
|
'@opentiny/vue-theme/theme': `${VITE_CDN_DOMAIN}/@opentiny/vue-theme@${importMapVersions.tinyVue}/theme/index.js`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const importMapStyles = [`${VITE_CDN_DOMAIN}/@opentiny/vue-theme@${importMapVersions.tinyVue}/index.css`]
|
const importMapStyles = [`${VITE_CDN_DOMAIN}/@opentiny/vue-theme@${importMapVersions.tinyVue}/index.css`]
|
||||||
|
|
||||||
config.plugins.push(monacoEditorPluginInstance, htmlPlugin(mode), importmapPlugin(importmap, importMapStyles))
|
config.plugins.push(
|
||||||
|
monacoEditorPluginInstance,
|
||||||
|
htmlPlugin(mode),
|
||||||
|
isLocalImportMap
|
||||||
|
? copyLocalImportMap({
|
||||||
|
importMap: importmap,
|
||||||
|
styleUrls: importMapStyles,
|
||||||
|
originCdnPrefix: VITE_CDN_DOMAIN,
|
||||||
|
base: getBaseUrlFromCli(config.base),
|
||||||
|
packageCopy: [
|
||||||
|
// 这两个包的js存在相对路径引用,不能单独拷贝一个文件,需要整个包拷贝
|
||||||
|
'@opentiny/vue-theme/theme-tool',
|
||||||
|
'@opentiny/vue-theme/theme'
|
||||||
|
]
|
||||||
|
})
|
||||||
|
: importmapPlugin(importmap, importMapStyles),
|
||||||
|
isCopyBundleDeps
|
||||||
|
? copyBundleDeps({
|
||||||
|
bundleFile: 'public/mock/bundle.json',
|
||||||
|
targetBundleFile: 'mock/bundle.json',
|
||||||
|
originCdnPrefix: VITE_CDN_DOMAIN, // mock 中bundle的域名当前和环境的VITE_CDN_DOMAIN一致
|
||||||
|
base: getBaseUrlFromCli(config.base)
|
||||||
|
}).plugin(command === 'serve')
|
||||||
|
: [],
|
||||||
|
isLocalImportMap
|
||||||
|
? copyPreviewImportMap({
|
||||||
|
importMapJson: './src/preview/src/preview/importMap.json',
|
||||||
|
targetImportMapJson: 'preview-import-map-static/preview-importmap.json',
|
||||||
|
originCdnPrefix: VITE_CDN_DOMAIN,
|
||||||
|
base: getBaseUrlFromCli(config.base),
|
||||||
|
packageCopyLib: [
|
||||||
|
// 以下的js存在相对路径引用,不能单独拷贝一个文件,需要整个包拷贝
|
||||||
|
'@vue/devtools-api'
|
||||||
|
]
|
||||||
|
})
|
||||||
|
: []
|
||||||
|
)
|
||||||
return config
|
return config
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue