Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

build: 公共依赖cdn解耦并增加开关控制 #360

Merged
merged 46 commits into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
986d7f8
build: external public cdn localize 公共cdn依赖包支持本地化
rhlin Mar 12, 2024
7659116
build: cdn外部依赖解耦,修复baseUrl获取
rhlin Mar 12, 2024
d3d6824
build: cdn依赖解耦 修正baseUrl获取方式
rhlin Mar 12, 2024
7973917
build: cdn依赖三方解耦,优化目录型拷贝
rhlin Mar 12, 2024
2d3c574
build: cdn依赖解耦,解决目录复制文件的相对路径问题
rhlin Mar 13, 2024
c8712a7
build(design-core): 修复monaco的worker使用cdn地址前缀的情况下打包失效
rhlin Mar 15, 2024
4e1cc0b
build: 本地开发也支持脱离cdn三方依赖
rhlin Mar 15, 2024
9fce65d
build: 去除代码注释
rhlin Mar 15, 2024
9ccd0e5
build: 三方cdn依赖解耦 物料bundle文件依赖支持替换cdn依赖
rhlin Mar 20, 2024
64413c2
build(design-core) 去除冗余用不到的文件和配置项硬编码
rhlin Mar 28, 2024
75929ec
build: 公共依赖cdn解耦测试完成 开关默认关闭
rhlin Mar 28, 2024
cf6da9d
refactor: 简化三方cdn依赖解耦的正则,改为path方法
rhlin Apr 1, 2024
ba19f07
refactor: 三方依赖解耦脚本代码优化,减少雷同的正则匹配
rhlin Apr 1, 2024
73ffc68
refactor: 三方cdn依赖解耦脚本 简化合并正则
rhlin Apr 1, 2024
ea5156d
Merge remote-tracking branch 'upstream/develop' into build-toggle-cdn
rhlin Apr 1, 2024
2e385d0
build: 三方cdn解耦 物料本地打包逻辑优化修正
rhlin Apr 2, 2024
c92d08f
build: 三方cdn依赖解耦,优化代码简化正则,修复计算版本号问题,修复函数名大小写问题
rhlin Apr 9, 2024
3f85722
build: 优化importMap版本站位符号
rhlin Apr 9, 2024
fb47d08
build: 三方cdn物料解耦 变量改为环境变量
rhlin Apr 9, 2024
f0cf45d
build: 三方cdn依赖解耦 补充处理复制文件夹时候的去重
rhlin Apr 10, 2024
e2deede
fix: 三方cdn解耦, 解决本地启动问题
rhlin Apr 18, 2024
676b366
Merge remote-tracking branch 'upstream/develop' into build-toggle-cdn
rhlin Apr 18, 2024
ea9778c
feat(preview): preview也支持cdn依赖解耦
rhlin Apr 19, 2024
ddecae8
refactor(desing-core/scripts): 重构复制cdn文件本地复制模块
rhlin Apr 20, 2024
e685ee7
build: 重构预览的importMap复制逻辑,修复两个importMap文件不存在
rhlin Apr 20, 2024
22a2101
build: 进一步优化monacoEditor地址,直接打包不再跨网络获取
rhlin Apr 20, 2024
6e93c1a
refactor(design-core/scripts): 调整复制应用importMap函数的参数顺序,与其他结构类似
rhlin Apr 20, 2024
3d267b1
refactor(design-core/script): 调整文件位置和文件引用顺序
rhlin Apr 20, 2024
7cd40c8
feat(design-core/preview): preview importMap.js 使用 importMap.json 数据归一
rhlin Apr 22, 2024
f95106d
fix(design-core/preview): 修复importJson的引用
rhlin Apr 22, 2024
1a6bdf9
fix: mock端口号订正,解决element-plus拖入画布后无法渲染
rhlin Apr 23, 2024
a0400f9
build(design-core/script): 修复临时安装包插件安装完包后返回目录不正确
rhlin Apr 24, 2024
f99deb5
fix: 修正monaco-editor的worker资源的打包地址
rhlin Apr 25, 2024
6e74402
build(design-core/script): 修复临时安装包插件安装完包后返回目录不正确
rhlin Apr 25, 2024
a1d7fb3
fix(design-core/preview): 修正cdn解耦preview获取动态的importMap.json的base路径问题
rhlin Apr 25, 2024
7246165
build: 三方cdn解耦,优化拷贝脚本,修复文件夹当文件拷贝当文件夹是包路径时候目标路径版本号丢失
rhlin Apr 25, 2024
7c499f2
build: 三方cdn解耦,解决包未安装的情况下,glob匹配不到文件导致打包不拷贝内容
rhlin Apr 25, 2024
a9de8cd
fix: 根据检视意见使用fs-extra readJsonSync替代utils工具函数
rhlin May 11, 2024
c892c7a
fix: 根据检视意见修改函数名大小写和端口号读取
rhlin May 11, 2024
c71b24f
feat: 三方物料解耦 preview变量替换增加注释
rhlin May 11, 2024
dc1ad0f
feat: 根据检视意见修改函数名字
rhlin May 11, 2024
707a075
refactor: 根据检视意见,将脚本函数的参数整改为对象,并把目录值迁移到参数默认值
rhlin May 11, 2024
d9b6710
docs(design-core/scripts): 三方cdn解耦 修正描述错误
rhlin May 12, 2024
b94d758
Merge remote-tracking branch 'upstream/develop' into build-toggle-cdn
rhlin May 13, 2024
85e42b2
fix: 三方cdn解耦 修正preview脚本TinyVue版本号
rhlin May 13, 2024
e11c76c
Merge remote-tracking branch 'upstream/develop' into build-toggle-cdn
rhlin May 13, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package-lock.json
yarn.lock
pnpm-lock.yaml
lerna-debug.log
packages/design-core/bundle-deps

# local env files
.env.local
Expand Down
1 change: 0 additions & 1 deletion packages/design-core/canvas.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link href="%VITE_CDN_DOMAIN%/@opentiny/[email protected]/index.css" rel="stylesheet" />
<style type="text/css">
.loading-warp {
display: flex;
Expand Down
4 changes: 3 additions & 1 deletion packages/design-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,11 @@
"rollup-plugin-polyfill-node": "^0.12.0",
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-visualizer": "^5.8.3",
"shelljs": "^0.8.5",
"svg-sprite-loader": "^6.0.11",
"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",
"vue-eslint-parser": "^8.0.1"
},
Expand Down
172 changes: 172 additions & 0 deletions packages/design-core/scripts/copyBundleDeps.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import fs from 'node:fs'
import path from 'node:path'
import shelljs from 'shelljs'
import { viteStaticCopy } from 'vite-plugin-static-copy'

export function readJsonFile(filename) {
const filepath = path.resolve(filename)
const content = fs.readFileSync(filepath, { encoding: 'utf-8' })
const json = JSON.parse(content)
return json
}
export function extraBundleCdnLink(filename, originCdnPrefix) {
const result = []
const bundle = readJsonFile(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.push(url)
}
})
}
})
return result.reduce((acc, cur) => {
if (!acc.includes(cur)) {
acc.push(cur)
}
return acc
}, [])
}

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 installPackageTemporary(packageNeedToInstall, tempDir, logger = console) {
return [
{
name: 'vite-plugin-install-package-temporary',
buildStart() {
if (packageNeedToInstall.some((pkg) => !pkg.exist)) {
let code = shelljs.mkdir('-p', tempDir).code
code ||
fs.writeFileSync(
path.resolve(tempDir, 'package.json'),
JSON.stringify(
{
name: 'bundle-deps',
dependencies: packageNeedToInstall.reduce((acc, cur) => {
acc[cur.packageName] = cur.version
return acc
}, {})
},
null,
2
),
{ encoding: 'utf-8' }
)
code = code || shelljs.cd(tempDir).code || shelljs.exec(`npm install`).code || shelljs.cd('../').code

if (code !== 0) {
logger.warn(`[vite-plugin-install-package-temporary]: bundle dependencies package install failed`)
} else {
logger.info(
`[vite-plugin-install-package-temporary]: bundle dependencies package install success, total ${packageNeedToInstall.length} package(s)`
)
}
} else {
logger.info(`[vite-plugin-install-package-temporary]: bundle dependencies packages exist, skip install `)
}
}
}
]
}

export function CopyBundleDeps(
bundleFile,
targetBundleFile,
originCdnPrefix,
base,
dir,
bundleTempDir = 'bundle-deps'
) {
const files = extraBundleCdnLink(bundleFile, originCdnPrefix).map((url) => {
const relativeUrl = url.replace(new RegExp('^' + originCdnPrefix + '/?'), '')
const packageName = relativeUrl.match(/^(.+?)@/)[1]
let version = relativeUrl.match(new RegExp('^' + packageName + '@([^/]+)'))[1]
const baseSlash = base.endsWith('/') ? '' : '/'
const filePathInPackage = `${relativeUrl.replace(new RegExp('^' + packageName + '@' + version), '')}`
let src = `node_modules/${packageName}${filePathInPackage}`
const sourceExist = fs.existsSync(path.resolve(src))
let sourceExistExternal = false
if (sourceExist) {
const content = readJsonFile(`node_modules/${packageName}/package.json`)
version = content.version
} else {
src = bundleTempDir + '/' + src
sourceExistExternal = fs.existsSync(path.resolve(src)) // 安装过的不重新安装
}
const newRelativeUrl = `${packageName}@${version}${filePathInPackage}`
return {
originUrl: url,
newUrl: `${base}${baseSlash}${dir}/${newRelativeUrl}`,
src,
dest: `${dir}/${newRelativeUrl}`.replace(/\/([^/]*?)$/, ''),
packageName,
version,
sourceExist,
sourceExistExternal,
transform: null // 物料的依赖目前暂定是需要mjs,暂不考虑相对链接问题
}
})

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
}, [])

if (packageNeedToInstall.length) {
files.forEach((file) => {
const samePackage = packageNeedToInstall.find(({ packageName }) => packageName === file.packageName)
if (samePackage) {
file.version = samePackage.version
}
})
}

const plugin = () => {
return [
...installPackageTemporary(packageNeedToInstall, bundleTempDir),
...viteStaticCopy({
targets: [
...files.map(({ src, dest, transform }) => ({
src,
dest,
transform
})),
{
src: bundleFile,
dest: path.dirname(targetBundleFile),
transform: (content) => {
const json = JSON.parse(content)
replaceBundleCdnLink(json, files)
return JSON.stringify(json, null, 2)
},
rename: path.basename(targetBundleFile),
overwrite: true // 覆盖public的
}
]
})
]
}
return {
plugin
}
}
77 changes: 77 additions & 0 deletions packages/design-core/scripts/copyExternal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import path from 'node:path'
import fg from 'fast-glob'
import { normalizePath } from 'vite'
import { viteStaticCopy } from 'vite-plugin-static-copy'
import { babelReplaceImportPathWithCertainFIleName } from './replaceImportPath.mjs'

export const useLocalImportMap = (flag, publicPath = '', dir = 'import-map-static') => {
if (!flag) {
return {
cdnPrefix: null,
distDir: null,
versionPlaceholder: null,
copyImportMapFilePlugin: (_) => null
}
}
const cdnPrefix = publicPath + (!publicPath || publicPath.endsWith('/') ? '' : '/') + dir
const versionPlaceholder = 'workspace'
const copyImportMapFilePlugin = (imports, packageCopy) => {
const files = Object.entries(imports).map(([libKey, libPath]) => {
const reg = new RegExp('^' + cdnPrefix + '/' + '(.*?)' + '@' + versionPlaceholder + '(.*?)$')
const packageName = libPath.match(reg)[1]
if (packageCopy.includes(libKey)) {
const srcPath = `node_modules/${packageName}`
const distFullPath = `${dir}/${packageName}@${versionPlaceholder}`
const distPath = path.dirname(distFullPath)
const packageDirName = path.basename(distFullPath)
const rename = (_filename, _fileExtension, fullPath) => {
return packageDirName + '/' + fullPath.replace(srcPath, '')
}
const transform = (content, filename) => {
if (filename.endsWith('.js')) {
const result = babelReplaceImportPathWithCertainFIleName(content, filename, console)
return result.code || content
}
return content
}
const onlyFiles = (globString) =>
fg.sync(globString + '/**/*', { onlyFiles: true }).map((p) => normalizePath(p)) // viteStaticCopy 自带的glob匹配无法过滤目录, 手动过滤目录作为数组传入
return [libKey, libPath, onlyFiles(srcPath), distPath, rename, transform]
}
const pathnameInPackage = libPath.match(reg)[2]
const srcPath = `node_modules/${packageName}${pathnameInPackage}`.replace(/\/$/, '')
const distPath = path.dirname(
`${dir}/${packageName}@${versionPlaceholder}${pathnameInPackage}`.replace(/\/$/, '')
)
return [libKey, libPath, srcPath, distPath, null, null]
})
const copyFiles = files
.map(([_libKey, _libPath, srcPath, distPath, rename, transform]) => ({
src: srcPath,
dest: distPath,
rename,
transform
}))
.reduce((acc, cur) => {
//去重
if (!acc.some((item) => item.src === cur.src && item.dest === cur.dest)) {
acc.push(cur)
}
return acc
}, [])
return viteStaticCopy({
targets: copyFiles
})
}
return {
cdnPrefix, // 替换VITE_CDN_DOMAIN
distDir: dir,
versionPlaceholder, //替换@version中的version
copyImportMapFilePlugin
}
}

export const getBaseUrlFromCli = (fallback = '') => {
const index = process.argv?.indexOf('--base')
return index > -1 ? process.argv[index + 1] || fallback : fallback
}
88 changes: 88 additions & 0 deletions packages/design-core/scripts/replaceImportPath.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
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
}

export function babelReplaceImportPathWithCertainFIleName(content, currentFilePath, logger) {
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
}

Loading
Loading