refactor: build tools (#2374)
* refactor: core/build and cli/build.js * fix: build * fix: bug * fix: replaceAll to replace * fix: node version check * fix: add require check * fix: esbuild other ext * fix: process json * fix: exlude jsx-runtime * feat: split chunk * fix: minify plugin client bundle * fix: compatibility * fix: support import() * feat: update docs * fix: server deps * feat: demo * fix: remove cjs treeshake * fix: local error * fix: bug * fix: lazy load * fix: rewrites * fix: remove dynamic import function * feat: doc demo * fix: codesanbox vite template * fix: codesanbox demo * fix: hide stackblitz * fix: revert rspack * fix: test bug * fix: delete console * fix: import dayjs locale --------- Co-authored-by: chenos <chenlinxh@gmail.com>
This commit is contained in:
		
							parent
							
								
									24179c4469
								
							
						
					
					
						commit
						08c5383bee
					
				
							
								
								
									
										11
									
								
								.buildrc.ts
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								.buildrc.ts
									
									
									
									
									
								
							| @ -1,11 +0,0 @@ | ||||
| export default { | ||||
|   target: 'node', | ||||
|   cjs: { type: 'babel', lazy: true }, | ||||
|   excludePkgs: [ | ||||
|     'core/build', | ||||
|     'core/cli', | ||||
|     'core/create-nocobase-app', | ||||
|     'core/devtools', | ||||
|     'app/client', | ||||
|   ], | ||||
| }; | ||||
							
								
								
									
										221
									
								
								.dumi/theme/slots/PreviewerActions.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										221
									
								
								.dumi/theme/slots/PreviewerActions.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,221 @@ | ||||
| import DumiPreviewerActions from 'dumi/theme-default/slots/PreviewerActions'; | ||||
| import React, { useRef, useEffect, useState } from 'react'; | ||||
| import { Spin } from 'antd' | ||||
| 
 | ||||
| import { IPreviewerProps } from 'dumi'; | ||||
| 
 | ||||
| const indexHtml = `<body>
 | ||||
|   <div id="root"></div> | ||||
|   <script type="module" src="/src/main.tsx"></script> | ||||
| </body> | ||||
| ` | ||||
| 
 | ||||
| const mainTsx = ` | ||||
| import React from 'react' | ||||
| import ReactDOM from 'react-dom/client' | ||||
| import App from './App' | ||||
| 
 | ||||
| ReactDOM.createRoot(document.getElementById('root')!).render( | ||||
|   <React.StrictMode> | ||||
|     <App /> | ||||
|   </React.StrictMode>, | ||||
| ) | ||||
| ` | ||||
| 
 | ||||
| const packageJson = ` | ||||
| { | ||||
|   "version": "0.0.0", | ||||
|   "type": "module", | ||||
|   "scripts": { | ||||
|     "dev": "vite", | ||||
|     "build": "tsc && vite build", | ||||
|     "preview": "vite preview" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "flat": "^5.0.2", | ||||
|     "react": "^18.2.0", | ||||
|     "react-dom": "^18.2.0", | ||||
|     "@types/react": "^18.2.15", | ||||
|     "@types/react-dom": "^18.2.7", | ||||
|     "@vitejs/plugin-react": "^4.0.3", | ||||
|     "less": "^4.2.0", | ||||
|     "typescript": "^5.0.2", | ||||
|     "vite": "^4.4.5" | ||||
|   } | ||||
| } | ||||
| ` | ||||
| 
 | ||||
| const tsConfigJson = ` | ||||
| { | ||||
|   "compilerOptions": { | ||||
|     "target": "ES2020", | ||||
|     "useDefineForClassFields": true, | ||||
|     "lib": [ | ||||
|       "ES2020", | ||||
|       "DOM", | ||||
|       "DOM.Iterable" | ||||
|     ], | ||||
|     "module": "ESNext", | ||||
|     "skipLibCheck": true, | ||||
|     "moduleResolution": "bundler", | ||||
|     "allowImportingTsExtensions": true, | ||||
|     "resolveJsonModule": true, | ||||
|     "isolatedModules": true, | ||||
|     "noEmit": true, | ||||
|     "jsx": "react-jsx", | ||||
|     "composite": true, | ||||
|     "strict": false, | ||||
|     "noUnusedLocals": true, | ||||
|     "noUnusedParameters": true, | ||||
|     "allowSyntheticDefaultImports": true, | ||||
|     "noFallthroughCasesInSwitch": true | ||||
|   }, | ||||
|   "include": [ | ||||
|     "src", | ||||
|     "vite.config.ts" | ||||
|   ] | ||||
| } | ||||
| ` | ||||
| 
 | ||||
| const viteConfigTs = ` | ||||
| import { defineConfig } from 'vite' | ||||
| import react from '@vitejs/plugin-react' | ||||
| 
 | ||||
| export default defineConfig({ | ||||
|   plugins: [react()], | ||||
| }) | ||||
| ` | ||||
| 
 | ||||
| const sandboxTask = ` | ||||
| { | ||||
|   "setupTasks": [ | ||||
|     { | ||||
|       "name": "Install Dependencies", | ||||
|       "command": "yarn install" | ||||
|     } | ||||
|   ], | ||||
|   "tasks": { | ||||
|     "dev": { | ||||
|       "name": "dev", | ||||
|       "command": "yarn dev", | ||||
|       "runAtStart": true, | ||||
|       "preview": { | ||||
|         "port": 5173 | ||||
|       } | ||||
|     }, | ||||
|     "build": { | ||||
|       "name": "build", | ||||
|       "command": "yarn build", | ||||
|       "runAtStart": false | ||||
|     }, | ||||
|     "preview": { | ||||
|       "name": "preview", | ||||
|       "command": "yarn preview", | ||||
|       "runAtStart": false | ||||
|     } | ||||
|   } | ||||
| } | ||||
| ` | ||||
| 
 | ||||
| function getCSBData(opts: IPreviewerProps, ext: string) { | ||||
| 
 | ||||
|   const files: Record< | ||||
|     string, | ||||
|     { | ||||
|       content: string; | ||||
|       isBinary: boolean; | ||||
|     } | ||||
|   > = {}; | ||||
|   const deps: Record<string, string> = {}; | ||||
|   const entryFileName = `index${ext}`; | ||||
| 
 | ||||
|   Object.entries(opts.asset.dependencies).forEach(([name, { type, value }]) => { | ||||
|     if (type === 'NPM') { | ||||
|       // generate dependencies
 | ||||
|       deps[name] = value; | ||||
|     } else { | ||||
|       // append other imported local files
 | ||||
|       files[name === entryFileName ? `src/App${ext}` : name] = { | ||||
|         content: value, | ||||
|         isBinary: false, | ||||
|       }; | ||||
|     } | ||||
|   }); | ||||
| 
 | ||||
|   // append package.json
 | ||||
|   let pkg = JSON.parse(packageJson) | ||||
|   try { | ||||
|     for (let key in deps) { | ||||
|       if (!pkg['devDependencies'][key]) { | ||||
|         pkg.dependencies[key] = deps[key] | ||||
|       } | ||||
|     } | ||||
|   } catch (e) { | ||||
|     console.log(e) | ||||
|   } | ||||
|   files['package.json'] = { | ||||
|     content: JSON.stringify( | ||||
|       { | ||||
|         name: opts.title, | ||||
|         ...pkg, | ||||
|       }, | ||||
|       null, | ||||
|       2, | ||||
|     ), | ||||
|     isBinary: false, | ||||
|   }; | ||||
| 
 | ||||
|   files['index.html'] = { content: indexHtml, isBinary: false }; | ||||
|   files['src/main.tsx'] = { content: mainTsx, isBinary: false }; | ||||
|   files['package.json'] = { content: JSON.stringify(pkg, null, 2), isBinary: false }; | ||||
|   files['.codesandbox/task.json'] = { content: sandboxTask, isBinary: false }; | ||||
|   files['tsconfig.json'] = { content: tsConfigJson, isBinary: false }; | ||||
|   files['vite.config.ts'] = { content: viteConfigTs, isBinary: false }; | ||||
| 
 | ||||
|   return { files }; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| export function openCodeSandbox(opts: IPreviewerProps) { | ||||
|   const isTSX = Boolean(opts.asset.dependencies?.['index.tsx']); | ||||
|   const ext = isTSX ? '.tsx' : '.jsx'; | ||||
|   return fetch("https://codesandbox.io/api/v1/sandboxes/define?json=1", { | ||||
|     method: "POST", | ||||
|     headers: { | ||||
|       "Content-Type": "application/json", | ||||
|       Accept: "application/json" | ||||
|     }, | ||||
|     body: JSON.stringify(getCSBData(opts, ext)) | ||||
|   }) | ||||
|     .then(x => x.json()) | ||||
|     .then(data => { | ||||
|       window.open(`https://codesandbox.io/p/sandbox/${data.sandbox_id}?file=/src/App${ext}`); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| const PreviewerActions: typeof DumiPreviewerActions = (props) => { | ||||
|   const div = useRef<HTMLDivElement>(null); | ||||
|   const [loading, setLoading] = useState(false); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     if (div.current) { | ||||
|       const elements = div.current.querySelectorAll('.dumi-default-previewer-actions'); | ||||
|       elements.forEach((element) => { | ||||
|         element.addEventListener('click', (e) => { | ||||
|           e.stopImmediatePropagation(); | ||||
|           setLoading(true); | ||||
|           openCodeSandbox(props).finally(() => { | ||||
|             setLoading(false); | ||||
|           }); | ||||
|         }) | ||||
|       }) | ||||
|     } | ||||
|   }, [div]) | ||||
| 
 | ||||
|   return <Spin spinning={loading}><div ref={div}><DumiPreviewerActions {...props} disabledActions={['STACKBLITZ']} /></div></Spin> | ||||
| }; | ||||
| 
 | ||||
| export default PreviewerActions; | ||||
| @ -5,6 +5,9 @@ | ||||
|     "packages/*/*" | ||||
|   ], | ||||
|   "license": "Apache-2.0", | ||||
|   "engines": { | ||||
|     "node": ">=16.0.0" | ||||
|   }, | ||||
|   "licenses": [ | ||||
|     { | ||||
|       "type": "Apache-2.0", | ||||
|  | ||||
| @ -1 +0,0 @@ | ||||
| export { default } from '@nocobase/plugin-api-doc/client'; | ||||
| @ -1,4 +1,3 @@ | ||||
| import { ACL } from './acl'; | ||||
| import minimatch from 'minimatch'; | ||||
| 
 | ||||
| export type SnippetOptions = { | ||||
| @ -7,7 +6,10 @@ export type SnippetOptions = { | ||||
| }; | ||||
| 
 | ||||
| class Snippet { | ||||
|   constructor(public name: string, public actions: Array<string>) {} | ||||
|   constructor( | ||||
|     public name: string, | ||||
|     public actions: Array<string>, | ||||
|   ) {} | ||||
| } | ||||
| 
 | ||||
| export type SnippetGroup = { | ||||
|  | ||||
| @ -8,7 +8,9 @@ process.env.MFSU_AD = 'none'; | ||||
| process.env.DID_YOU_KNOW = 'none'; | ||||
| 
 | ||||
| const pluginPrefix = (process.env.PLUGIN_PACKAGE_PREFIX || '').split(',').filter((item) => !item.includes('preset')); // 因为现在 preset 是直接引入的,所以不能忽略,如果以后 preset 也是动态插件的形式引入,那么这里可以去掉
 | ||||
| const pluginDirs = 'packages/plugins/,packages/samples/'.split(',').map((item) => path.join(process.cwd(), item)); | ||||
| 
 | ||||
| const pluginDirs = (process.env.PLUGIN_PATH || 'packages/plugins/,packages/samples/') | ||||
|   .split(',').map(item => path.join(__dirname, '..', '..', '..', '..', item)); | ||||
| 
 | ||||
| const outputPluginPath = path.join(__dirname, 'src', '.plugins'); | ||||
| const indexGenerator = new IndexGenerator(outputPluginPath, pluginDirs); | ||||
| @ -51,6 +53,9 @@ export default defineConfig({ | ||||
|     edge: 79, | ||||
|     safari: 12, | ||||
|   }, | ||||
|   codeSplitting: { | ||||
|     jsStrategy: 'depPerChunk' | ||||
|   }, | ||||
|   chainWebpack(config, { env }) { | ||||
|     if (env === 'production') { | ||||
|       config.plugin('ignore nocobase plugins').use(require('webpack').IgnorePlugin, [ | ||||
|  | ||||
| @ -1 +0,0 @@ | ||||
| Used in bin/father.js to determine if it is in the local debug state. | ||||
| @ -4,7 +4,7 @@ const { existsSync } = require('fs'); | ||||
| const { join } = require('path'); | ||||
| const yParser = require('yargs-parser'); | ||||
| const chalk = require('chalk'); | ||||
| const signale = require('signale'); | ||||
| const { build } = require('../lib'); | ||||
| 
 | ||||
| // print version and @local
 | ||||
| const args = yParser(process.argv.slice(2), { | ||||
| @ -26,46 +26,4 @@ const updater = require('update-notifier'); | ||||
| const pkg = require('../package.json'); | ||||
| updater({ pkg }).notify({ defer: true }); | ||||
| 
 | ||||
| function stripEmptyKeys(obj) { | ||||
|   Object.keys(obj).forEach((key) => { | ||||
|     if (!obj[key] || (Array.isArray(obj[key]) && !obj[key].length)) { | ||||
|       delete obj[key]; | ||||
|     } | ||||
|   }); | ||||
|   return obj; | ||||
| } | ||||
| 
 | ||||
| function build() { | ||||
|   // Parse buildArgs from cli
 | ||||
|   const buildArgs = stripEmptyKeys({ | ||||
|     esm: args.esm && { type: args.esm === true ? 'rollup' : args.esm }, | ||||
|     cjs: args.cjs && { type: args.cjs === true ? 'rollup' : args.cjs }, | ||||
|     umd: args.umd && { name: args.umd === true ? undefined : args.umd }, | ||||
|     file: args.file, | ||||
|     target: args.target, | ||||
|     entry: args._, | ||||
|     config: args.config, | ||||
|   }); | ||||
| 
 | ||||
|   if (buildArgs.file && buildArgs.entry && buildArgs.entry.length > 1) { | ||||
|     signale.error( | ||||
|       new Error(`Cannot specify file when have multiple entries (${buildArgs.entry.join(', ')})`) | ||||
|     ); | ||||
|     process.exit(1); | ||||
|   } | ||||
| 
 | ||||
|   require('../lib/build') | ||||
|     .default({ | ||||
|       cwd: args.root || process.cwd(), | ||||
|       watch: args.w || args.watch, | ||||
|       clean: args.clean, | ||||
|       buildArgs, | ||||
|       packages: args._ || [], | ||||
|     }) | ||||
|     .catch((e) => { | ||||
|       signale.error(e); | ||||
|       process.exit(1); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| build(); | ||||
| build(args._); | ||||
|  | ||||
| @ -8,76 +8,33 @@ | ||||
|   }, | ||||
|   "typings": "./index.d.ts", | ||||
|   "dependencies": { | ||||
|     "@babel/core": "7.22.5", | ||||
|     "@babel/plugin-proposal-class-properties": "7.18.6", | ||||
|     "@babel/plugin-proposal-decorators": "7.22.5", | ||||
|     "@babel/plugin-proposal-do-expressions": "7.22.5", | ||||
|     "@babel/plugin-proposal-export-default-from": "7.22.5", | ||||
|     "@babel/plugin-proposal-export-namespace-from": "7.18.9", | ||||
|     "@babel/plugin-proposal-nullish-coalescing-operator": "7.18.6", | ||||
|     "@babel/plugin-proposal-optional-chaining": "7.21.0", | ||||
|     "@babel/plugin-syntax-dynamic-import": "7.8.3", | ||||
|     "@babel/plugin-transform-modules-commonjs": "7.22.5", | ||||
|     "@babel/plugin-transform-runtime": "7.22.5", | ||||
|     "@babel/preset-env": "7.12.1", | ||||
|     "@babel/preset-react": "7.22.5", | ||||
|     "@babel/preset-typescript": "7.22.5", | ||||
|     "@babel/register": "7.22.5", | ||||
|     "@hapi/topo": "^6.0.0", | ||||
|     "@lerna/filter-packages": "4.0.0", | ||||
|     "@lerna/project": "4.0.0", | ||||
|     "@lerna/query-graph": "4.0.0", | ||||
|     "@rollup/plugin-babel": "6.0.3", | ||||
|     "@rollup/plugin-commonjs": "25.0.1", | ||||
|     "@rollup/plugin-inject": "5.0.3", | ||||
|     "@rollup/plugin-json": "6.0.0", | ||||
|     "@rollup/plugin-node-resolve": "15.1.0", | ||||
|     "@rollup/plugin-replace": "5.0.2", | ||||
|     "@rollup/plugin-url": "8.0.1", | ||||
|     "@svgr/rollup": "5.5.0", | ||||
|     "@vercel/ncc": "0.36.1", | ||||
|     "ajv": "6.12.6", | ||||
|     "autoprefixer": "9.6.0", | ||||
|     "babel-plugin-istanbul": "^5.2.0", | ||||
|     "babel-plugin-react-require": "3.1.1", | ||||
|     "chalk": "2.4.2", | ||||
|     "chokidar": "^3.0.2", | ||||
|     "es5-imcompatible-versions": "^0.1.37", | ||||
|     "fast-glob": "3.3.0", | ||||
|     "glob": "^7.1.4", | ||||
|     "gulp-if": "2.0.2", | ||||
|     "gulp-less": "^5.0.0", | ||||
|     "gulp-plumber": "^1.2.1", | ||||
|     "gulp": "4.0.2", | ||||
|     "@types/gulp": "^4.0.13", | ||||
|     "gulp-typescript": "6.0.0-alpha.1", | ||||
|     "less": "4.1.3", | ||||
|     "less-plugin-npm-import": "2.1.0", | ||||
|     "lodash": "4.17.21", | ||||
|     "pkg-up": "3.1.0", | ||||
|     "rimraf": "2.6.3", | ||||
|     "rollup": "3.25.1", | ||||
|     "rollup-plugin-postcss": "4.0.2", | ||||
|     "rollup-plugin-terser": "7.0.2", | ||||
|     "rollup-plugin-typescript2": "0.34.1", | ||||
|     "semver": "6.1.1", | ||||
|     "signale": "1.4.0", | ||||
|     "slash2": "2.0.0", | ||||
|     "temp-dir": "2.0.0", | ||||
|     "through2": "3.0.1", | ||||
|     "ts-loader": "^9.4.3", | ||||
|     "tsup": "7.1.0", | ||||
|     "tsup": "7.2.0", | ||||
|     "typescript": "5.1.3", | ||||
|     "update-notifier": "3.0.0", | ||||
|     "vinyl-fs": "3.0.3", | ||||
|     "vite-plugin-lib-inject-css": "1.2.0", | ||||
|     "vite-plugin-css-injected-by-js": "^3.2.1", | ||||
|     "yargs-parser": "13.1.2" | ||||
|     "yargs-parser": "13.1.2", | ||||
|     "@types/lerna__project": "5.1.0", | ||||
|     "@types/lerna__package": "5.1.0", | ||||
|     "@babel/core": "7.22.10", | ||||
|     "@babel/preset-env": "7.22.10", | ||||
|     "@babel/plugin-transform-modules-amd": "7.22.5" | ||||
|   }, | ||||
|   "license": "Apache-2.0", | ||||
|   "scripts": { | ||||
|     "build": "umi-tools build" | ||||
|     "build": "tsup" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@types/gulp-plumber": "^0.0.32", | ||||
|     "umi-tools": "^0.4.0" | ||||
|   }, | ||||
|   "gitHead": "ce588eefb0bfc50f7d5bbee575e0b5e843bf6644" | ||||
| } | ||||
|  | ||||
| @ -1,272 +0,0 @@ | ||||
| import { join, extname, relative } from "path"; | ||||
| import { existsSync, readFileSync, statSync } from "fs"; | ||||
| import vfs from "vinyl-fs"; | ||||
| import signale from "signale"; | ||||
| import lodash from "lodash"; | ||||
| import rimraf from "rimraf"; | ||||
| import through from "through2"; | ||||
| import slash from "slash2"; | ||||
| import * as chokidar from "chokidar"; | ||||
| import * as babel from "@babel/core"; | ||||
| import gulpTs from "gulp-typescript"; | ||||
| import gulpLess from "gulp-less"; | ||||
| import gulpPlumber from "gulp-plumber"; | ||||
| import gulpIf from "gulp-if"; | ||||
| import chalk from "chalk"; | ||||
| import fs from 'fs-extra' | ||||
| import getBabelConfig from "./getBabelConfig"; | ||||
| import { Dispose, IBundleOptions } from "./types"; | ||||
| import * as ts from "typescript"; | ||||
| 
 | ||||
| interface IBabelOpts { | ||||
|   cwd: string; | ||||
|   rootPath?: string; | ||||
|   type: "esm" | "cjs"; | ||||
|   target?: "browser" | "node"; | ||||
|   log?: (string) => void; | ||||
|   watch?: boolean; | ||||
|   dispose?: Dispose[]; | ||||
|   isPlugin?: boolean; | ||||
|   importLibToEs?: boolean; | ||||
|   bundleOpts: IBundleOptions; | ||||
| } | ||||
| 
 | ||||
| interface ITransformOpts { | ||||
|   file: { | ||||
|     contents: string; | ||||
|     path: string; | ||||
|   }; | ||||
|   type: "esm" | "cjs"; | ||||
| } | ||||
| 
 | ||||
| export default async function (opts: IBabelOpts) { | ||||
|   const { | ||||
|     cwd, | ||||
|     rootPath, | ||||
|     type, | ||||
|     watch, | ||||
|     dispose, | ||||
|     importLibToEs, | ||||
|     log, | ||||
|     isPlugin = false, | ||||
|     bundleOpts: { | ||||
|       target = "browser", | ||||
|       runtimeHelpers, | ||||
|       extraBabelPresets = [], | ||||
|       extraBabelPlugins = [], | ||||
|       browserFiles = [], | ||||
|       nodeFiles = [], | ||||
|       nodeVersion, | ||||
|       disableTypeCheck, | ||||
|       cjs, | ||||
|       lessInBabelMode, | ||||
|     }, | ||||
|   } = opts; | ||||
|   const srcPath = join(cwd, "src"); | ||||
|   const targetDir = type === "esm" ? "es" : isPlugin ? 'dist' : "lib"; | ||||
|   const targetPath = join(cwd, targetDir); | ||||
| 
 | ||||
|   if (!isPlugin) { | ||||
|     log(chalk.gray(`Clean ${targetDir} directory`)); | ||||
|     rimraf.sync(targetPath); | ||||
|   } else { | ||||
|     if (fs.existsSync(targetPath)) { | ||||
|       // exclude node_modules
 | ||||
|       const files = fs.readdirSync(targetPath, { recursive: false }) as string[]; | ||||
|       files.forEach((file) => { | ||||
|         if (file !== 'node_modules') { | ||||
|           rimraf.sync(join(targetPath, file)); | ||||
|         } | ||||
|       }) | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   function transform(opts: ITransformOpts) { | ||||
|     const { file, type } = opts; | ||||
|     const { opts: babelOpts, isBrowser } = getBabelConfig({ | ||||
|       target, | ||||
|       type, | ||||
|       typescript: true, | ||||
|       runtimeHelpers, | ||||
|       filePath: slash(relative(cwd, file.path)), | ||||
|       browserFiles, | ||||
|       nodeFiles, | ||||
|       nodeVersion, | ||||
|       lazy: cjs && cjs.lazy, | ||||
|       lessInBabelMode, | ||||
|     }); | ||||
|     if (importLibToEs && type === "esm") { | ||||
|       babelOpts.plugins.push(require.resolve("../lib/importLibToEs")); | ||||
|     } | ||||
|     babelOpts.presets.push(...extraBabelPresets); | ||||
|     babelOpts.plugins.push(...extraBabelPlugins); | ||||
| 
 | ||||
|     const relFile = slash(file.path).replace(`${cwd}/`, ""); | ||||
|     log( | ||||
|       `Transform to ${type} for ${chalk[isBrowser ? "yellow" : "blue"]( | ||||
|         relFile | ||||
|       )}` | ||||
|     ); | ||||
| 
 | ||||
|     return babel.transform(file.contents, { | ||||
|       ...babelOpts, | ||||
|       filename: file.path, | ||||
|       // 不读取外部的babel.config.js配置文件,全采用babelOpts中的babel配置来构建
 | ||||
|       configFile: false, | ||||
|     }).code; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * tsconfig.json is not valid json file | ||||
|    * https://github.com/Microsoft/TypeScript/issues/20384
 | ||||
|    */ | ||||
|   function parseTsconfig(path: string) { | ||||
|     const readFile = (path: string) => readFileSync(path, "utf-8"); | ||||
|     const result = ts.readConfigFile(path, readFile); | ||||
|     if (result.error) { | ||||
|       return; | ||||
|     } | ||||
|     const pkgTsConfig = result.config; | ||||
|     if (pkgTsConfig.extends) { | ||||
|       const rootTsConfigPath = slash(relative(cwd, pkgTsConfig.extends)); | ||||
|       const rootTsConfig = parseTsconfig(rootTsConfigPath); | ||||
|       if (rootTsConfig) { | ||||
|         const mergedConfig = { | ||||
|           ...rootTsConfig, | ||||
|           ...pkgTsConfig, | ||||
|           compilerOptions: { | ||||
|             ...rootTsConfig.compilerOptions, | ||||
|             ...pkgTsConfig.compilerOptions, | ||||
|           }, | ||||
|         }; | ||||
|         return mergedConfig; | ||||
|       } | ||||
|     } | ||||
|     return pkgTsConfig; | ||||
|   } | ||||
| 
 | ||||
|   function getTsconfigCompilerOptions(path: string) { | ||||
|     const config = parseTsconfig(path); | ||||
|     return config ? config.compilerOptions : undefined; | ||||
|   } | ||||
| 
 | ||||
|   function getTSConfig() { | ||||
|     const tsconfigPath = join(cwd, "tsconfig.json"); | ||||
|     const templateTsconfigPath = join(__dirname, "../template/tsconfig.json"); | ||||
| 
 | ||||
|     if (existsSync(tsconfigPath)) { | ||||
|       return getTsconfigCompilerOptions(tsconfigPath) || {}; | ||||
|     } | ||||
|     if (rootPath && existsSync(join(rootPath, "tsconfig.json"))) { | ||||
|       return getTsconfigCompilerOptions(join(rootPath, "tsconfig.json")) || {}; | ||||
|     } | ||||
|     return getTsconfigCompilerOptions(templateTsconfigPath) || {}; | ||||
|   } | ||||
| 
 | ||||
|   function createStream(src) { | ||||
|     const tsConfig = getTSConfig(); | ||||
|     const babelTransformRegexp = disableTypeCheck ? /\.(t|j)sx?$/ : /\.jsx?$/; | ||||
| 
 | ||||
|     function isTsFile(path) { | ||||
|       return /\.tsx?$/.test(path) && !path.endsWith(".d.ts"); | ||||
|     } | ||||
| 
 | ||||
|     function isTransform(path) { | ||||
|       if (isPlugin) return false | ||||
|       return babelTransformRegexp.test(path) && !path.endsWith(".d.ts"); | ||||
|     } | ||||
|     return vfs | ||||
|       .src(src, { | ||||
|         allowEmpty: true, | ||||
|         base: srcPath, | ||||
|       }) | ||||
|       .pipe(watch ? gulpPlumber() : through.obj()) | ||||
|       .pipe( | ||||
|         gulpIf((f) => !disableTypeCheck && isTsFile(f.path), gulpTs(tsConfig)) | ||||
|       ) | ||||
|       .pipe( | ||||
|         gulpIf( | ||||
|           (f) => lessInBabelMode && /\.less$/.test(f.path), | ||||
|           gulpLess(lessInBabelMode || {}) | ||||
|         ) | ||||
|       ) | ||||
|       .pipe( | ||||
|         gulpIf( | ||||
|           (f) => isTransform(f.path), | ||||
|           through.obj((file, env, cb) => { | ||||
|             try { | ||||
|               file.contents = Buffer.from( | ||||
|                 transform({ | ||||
|                   file, | ||||
|                   type, | ||||
|                 }) | ||||
|               ); | ||||
|               // .jsx -> .js
 | ||||
|               file.path = file.path.replace(extname(file.path), ".js"); | ||||
|               cb(null, file); | ||||
|             } catch (e) { | ||||
|               signale.error(`Compiled faild: ${file.path}`); | ||||
|               console.log(e); | ||||
|               cb(null); | ||||
|             } | ||||
|           }) | ||||
|         ) | ||||
|     ) | ||||
|       .pipe(vfs.dest(targetPath)) | ||||
|   } | ||||
| 
 | ||||
|   return new Promise((resolve) => { | ||||
|     const patterns = [ | ||||
|       isPlugin ? join(srcPath, "**/*.{ts,tsx}") : join(srcPath, "**/*"), | ||||
|       `!${join(srcPath, "**/fixtures{,/**}")}`, | ||||
|       `!${join(srcPath, "**/demos{,/**}")}`, | ||||
|       `!${join(srcPath, "**/__test__{,/**}")}`, | ||||
|       `!${join(srcPath, "**/__tests__{,/**}")}`, | ||||
|       `!${join(srcPath, "**/*.mdx")}`, | ||||
|       `!${join(srcPath, "**/*.md")}`, | ||||
|       `!${join(srcPath, "**/*.+(test|e2e|spec).+(js|jsx|ts|tsx)")}`, | ||||
|       `!${join(srcPath, "**/tsconfig{,.*}.json")}`, | ||||
|       `!${join(srcPath, ".umi{,-production,-test}{,/**}")}`, | ||||
|     ]; | ||||
|     createStream(patterns).on("end", () => { | ||||
|       if (watch) { | ||||
|         log( | ||||
|           chalk.magenta( | ||||
|             `Start watching ${slash(srcPath).replace( | ||||
|               `${cwd}/`, | ||||
|               "" | ||||
|             )} directory...` | ||||
|           ) | ||||
|         ); | ||||
|         const watcher = chokidar.watch(patterns, { | ||||
|           ignoreInitial: true, | ||||
|         }); | ||||
| 
 | ||||
|         const files = []; | ||||
|         function compileFiles() { | ||||
|           while (files.length) { | ||||
|             createStream(files.pop()); | ||||
|           } | ||||
|         } | ||||
| 
 | ||||
|         const debouncedCompileFiles = lodash.debounce(compileFiles, 1000); | ||||
|         watcher.on("all", (event, fullPath) => { | ||||
|           const relPath = fullPath.replace(srcPath, ""); | ||||
|           log( | ||||
|             `[${event}] ${slash(join(srcPath, relPath)).replace(`${cwd}/`, "")}` | ||||
|           ); | ||||
|           if (!existsSync(fullPath)) return; | ||||
|           if (statSync(fullPath).isFile()) { | ||||
|             if (!files.includes(fullPath)) files.push(fullPath); | ||||
|             debouncedCompileFiles(); | ||||
|           } | ||||
|         }); | ||||
|         process.once("SIGINT", () => { | ||||
|           watcher.close(); | ||||
|         }); | ||||
|         dispose?.push(() => watcher.close()); | ||||
|       } | ||||
|       resolve(); | ||||
|     }); | ||||
|   }); | ||||
| } | ||||
| @ -1,52 +0,0 @@ | ||||
| import { join, basename, sep } from 'path'; | ||||
| import { getPackagesSync } from '@lerna/project'; | ||||
| import { existsSync, readdirSync, renameSync, statSync } from 'fs'; | ||||
| import mkdirp from 'mkdirp'; | ||||
| import rimraf from 'rimraf'; | ||||
| import build from './build'; | ||||
| 
 | ||||
| function moveEsLibToDist(cwd) { | ||||
|   ['es', 'lib'].forEach(dir => { | ||||
|     const absDirPath = join(cwd, dir); | ||||
|     const absDistPath = join(cwd, 'dist'); | ||||
|     if (existsSync(absDirPath)) { | ||||
|       mkdirp.sync(absDistPath); | ||||
|       renameSync(absDirPath, join(absDistPath, dir)); | ||||
|     } | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| describe('father build', () => { | ||||
|   const rootConfigMapping = { | ||||
|     'lerna-root-config-override': { cjs: 'rollup', esm: false }, | ||||
|   }; | ||||
| 
 | ||||
|   require('test-build-result')({ | ||||
|     root: join(__dirname, './fixtures/build'), | ||||
|     build({ cwd }) { | ||||
|       process.chdir(cwd); | ||||
|       rimraf.sync(join(cwd, 'dist')); | ||||
|       return build({ cwd, rootConfig: rootConfigMapping[basename(cwd)] }).then(() => { | ||||
|         // babel
 | ||||
|         moveEsLibToDist(cwd); | ||||
| 
 | ||||
|         // lerna
 | ||||
|         if (existsSync(join(cwd, 'lerna.json'))) { | ||||
|           mkdirp.sync(join(cwd, 'dist')); | ||||
|           const pkgs = getPackagesSync(cwd) | ||||
|           for (let pkg of pkgs) { | ||||
|             | ||||
|             const pkgPath = pkg.contents; | ||||
|              | ||||
|             if (!statSync(pkgPath).isDirectory()) continue; | ||||
|             moveEsLibToDist(pkgPath); | ||||
|             renameSync( | ||||
|               join(pkgPath, 'dist'), | ||||
|               join(cwd, 'dist', pkgPath.split(sep).pop()) | ||||
|             ); | ||||
|           } | ||||
|         } | ||||
|       }); | ||||
|     }, | ||||
|   }); | ||||
| }); | ||||
| @ -1,287 +1,103 @@ | ||||
| import * as assert from 'assert'; | ||||
| import execa from 'execa'; | ||||
| import chalk from 'chalk'; | ||||
| import { existsSync, readFileSync } from 'fs'; | ||||
| import { merge } from 'lodash'; | ||||
| import { isAbsolute, join, sep } from 'path'; | ||||
| import rimraf from 'rimraf'; | ||||
| import signale from 'signale'; | ||||
| import babel from './babel'; | ||||
| import { buildPluginClient, buildPluginServer, deleteJsFiles } from './buildPlugin'; | ||||
| import getUserConfig, { CONFIG_FILES } from './getUserConfig'; | ||||
| import randomColor from './randomColor'; | ||||
| import registerBabel from './registerBabel'; | ||||
| import rollup from './rollup'; | ||||
| import { Dispose, IBundleOptions, IBundleTypeOutput, ICjs, IEsm, IOpts } from './types'; | ||||
| import { getExistFiles, getLernaPackages } from './utils'; | ||||
| import path from 'path'; | ||||
| import { | ||||
|   PACKAGES_PATH, | ||||
|   getPluginPackages, | ||||
|   CORE_CLIENT, | ||||
|   CORE_APP, | ||||
|   getCjsPackages, | ||||
|   getPresetsPackages, | ||||
|   ROOT_PATH, | ||||
| } from './constant'; | ||||
| import { buildClient } from './buildClient'; | ||||
| import { buildCjs } from './buildCjs'; | ||||
| import { buildPlugin } from './buildPlugin'; | ||||
| import { buildDeclaration } from './buildDeclaration'; | ||||
| import { PkgLog, getPkgLog, toUnixPath, getPackageJson } from './utils'; | ||||
| import { getPackages } from './utils/getPackages'; | ||||
| import { Package } from '@lerna/package'; | ||||
| 
 | ||||
| export function getBundleOpts(opts: IOpts): IBundleOptions[] { | ||||
|   const { cwd, buildArgs = {}, rootConfig = {} } = opts; | ||||
|   const entry = getExistFiles({ | ||||
| export async function build(pkgs: string[]) { | ||||
|   const packages = getPackages(pkgs); | ||||
|   const pluginPackages = getPluginPackages(packages); | ||||
|   const cjsPackages = getCjsPackages(packages); | ||||
|   const presetsPackages = getPresetsPackages(packages); | ||||
| 
 | ||||
|   // core/*
 | ||||
|   await buildPackages(cjsPackages, 'lib', buildCjs); | ||||
|   const clientCore = packages.find((item) => item.location === CORE_CLIENT); | ||||
|   if (clientCore) { | ||||
|     await buildPackage(clientCore, 'es', buildClient); | ||||
|   } | ||||
| 
 | ||||
|   // plugins/*、samples/*
 | ||||
|   await buildPackages(pluginPackages, 'dist', buildPlugin); | ||||
| 
 | ||||
|   // presets/*
 | ||||
|   await buildPackages(presetsPackages, 'lib', buildCjs); | ||||
| 
 | ||||
|   // core/app
 | ||||
|   const appClient = packages.find((item) => item.location === CORE_APP); | ||||
|   if (appClient) { | ||||
|     await runScript(['umi', 'build'], ROOT_PATH, { | ||||
|       APP_ROOT: path.join(CORE_APP, 'client'), | ||||
|     }); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export async function buildPackages( | ||||
|   packages: Package[], | ||||
|   targetDir: string, | ||||
|   doBuildPackage: (cwd: string, sourcemap: boolean, log?: PkgLog) => Promise<any>, | ||||
| ) { | ||||
|   for await (const pkg of packages) { | ||||
|     await buildPackage(pkg, targetDir, doBuildPackage); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export async function buildPackage( | ||||
|   pkg: Package, | ||||
|   targetDir: string, | ||||
|   doBuildPackage: (cwd: string, sourcemap: boolean, log?: PkgLog) => Promise<any>, | ||||
| ) { | ||||
|   const sourcemap = process.argv.includes('--sourcemap'); | ||||
|   const noDeclaration = process.argv.includes('--no-dts'); | ||||
|   const log = getPkgLog(pkg.name); | ||||
|   const packageJson = getPackageJson(pkg.location); | ||||
|   log(`${chalk.bold(toUnixPath(pkg.location.replace(PACKAGES_PATH, '').slice(1)))} build start`); | ||||
| 
 | ||||
|   // prebuild
 | ||||
|   if (packageJson?.scripts?.prebuild) { | ||||
|     log('prebuild'); | ||||
|     await runScript(['prebuild'], pkg.location); | ||||
|     await packageJson.prebuild(pkg.location); | ||||
|   } | ||||
| 
 | ||||
|   // build source
 | ||||
|   await doBuildPackage(pkg.location, sourcemap, log); | ||||
| 
 | ||||
|   // build declaration
 | ||||
|   if (!noDeclaration) { | ||||
|     log('build declaration'); | ||||
|     await buildDeclaration(pkg.location, targetDir); | ||||
|   } | ||||
| 
 | ||||
|   // postbuild
 | ||||
|   if (packageJson?.scripts?.postbuild) { | ||||
|     log('postbuild'); | ||||
|     await runScript(['postbuild'], pkg.location); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function runScript(args: string[], cwd: string, envs: Record<string, string> = {}) { | ||||
|   return execa('yarn', args, { | ||||
|     cwd, | ||||
|     files: [ | ||||
|       'src/index.tsx', | ||||
|       'src/index.ts', | ||||
|       'src/index.jsx', | ||||
|       'src/index.js', | ||||
|       'src/server/index.ts', | ||||
|       'src/server/index.js', | ||||
|       'src/client/index.js', | ||||
|       'src/client/index.ts', | ||||
|       'src/client/index.tsx', | ||||
|     ], | ||||
|     onlyOne: false, | ||||
|     returnRelative: true, | ||||
|   }); | ||||
|   const userConfig = getUserConfig({ cwd, customPath: buildArgs.config }); | ||||
|   const userConfigs = Array.isArray(userConfig) ? userConfig : [userConfig]; | ||||
|   return (userConfigs as any).map((userConfig) => { | ||||
|     const bundleOpts = merge( | ||||
|       { | ||||
|         entry, | ||||
|       }, | ||||
|       rootConfig, | ||||
|       userConfig, | ||||
|       buildArgs, | ||||
|     ); | ||||
| 
 | ||||
|     // Support config esm: 'rollup' and cjs: 'rollup'
 | ||||
|     if (typeof bundleOpts.esm === 'string') { | ||||
|       bundleOpts.esm = { type: bundleOpts.esm }; | ||||
|     } | ||||
|     if (typeof bundleOpts.cjs === 'string') { | ||||
|       bundleOpts.cjs = { type: bundleOpts.cjs }; | ||||
|     } | ||||
| 
 | ||||
|     return bundleOpts; | ||||
|     stdio: 'inherit', | ||||
|     env: { | ||||
|       ...process.env, | ||||
|       ...envs, | ||||
|       NODE_ENV: 'production', | ||||
|     }, | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| function validateBundleOpts(bundleOpts: IBundleOptions, { cwd, rootPath }) { | ||||
|   if (bundleOpts.runtimeHelpers) { | ||||
|     const pkgPath = join(cwd, 'package.json'); | ||||
|     assert.ok(existsSync(pkgPath), `@babel/runtime dependency is required to use runtimeHelpers`); | ||||
|     const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')); | ||||
|     assert.ok( | ||||
|       (pkg.dependencies || {})['@babel/runtime'], | ||||
|       `@babel/runtime dependency is required to use runtimeHelpers`, | ||||
|     ); | ||||
|   } | ||||
|   if (bundleOpts.cjs && (bundleOpts.cjs as ICjs).lazy && (bundleOpts.cjs as ICjs).type === 'rollup') { | ||||
|     throw new Error( | ||||
|       ` | ||||
| cjs.lazy don't support rollup. | ||||
|     `.trim(),
 | ||||
|     ); | ||||
|   } | ||||
|   if (!bundleOpts.esm && !bundleOpts.cjs && !bundleOpts.umd) { | ||||
|     throw new Error( | ||||
|       ` | ||||
| None format of ${chalk.cyan( | ||||
|         'cjs | esm | umd', | ||||
|       )} is configured, checkout https://github.com/umijs/father for usage details.
 | ||||
| `.trim(),
 | ||||
|     ); | ||||
|   } | ||||
|   if (bundleOpts.entry) { | ||||
|     const tsConfigPath = join(cwd, 'tsconfig.json'); | ||||
|     const tsConfig = existsSync(tsConfigPath) || (rootPath && existsSync(join(rootPath, 'tsconfig.json'))); | ||||
|     if ( | ||||
|       !tsConfig && | ||||
|       ((Array.isArray(bundleOpts.entry) && bundleOpts.entry.some(isTypescriptFile)) || | ||||
|         (!Array.isArray(bundleOpts.entry) && isTypescriptFile(bundleOpts.entry))) | ||||
|     ) { | ||||
|       signale.info(`Project using ${chalk.cyan('typescript')} but tsconfig.json not exists. Use default config.`); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function isTypescriptFile(filePath) { | ||||
|   return filePath.endsWith('.ts') || filePath.endsWith('.tsx'); | ||||
| } | ||||
| 
 | ||||
| function isPluginPackage(name: string) { | ||||
|   const prefixes = (process.env.PLUGIN_PACKAGE_PREFIX || '').split(','); | ||||
|   for (const prefix of prefixes) { | ||||
|     if (prefix.includes('preset')) { | ||||
|       continue; | ||||
|     } | ||||
|     if (name.startsWith(prefix)) { | ||||
|       return true; | ||||
|     } | ||||
|   } | ||||
|   return false; | ||||
| } | ||||
| 
 | ||||
| interface IExtraBuildOpts { | ||||
|   pkg?: string | { name?: string }; | ||||
| } | ||||
| 
 | ||||
| export async function build(opts: IOpts, extraOpts: IExtraBuildOpts = {}) { | ||||
|   const { cwd, rootPath, watch, buildArgs = {}, clean = true } = opts; | ||||
|   const { pkg } = extraOpts; | ||||
| 
 | ||||
|   const dispose: Dispose[] = []; | ||||
| 
 | ||||
|   const customConfigPath = | ||||
|     buildArgs.config && (isAbsolute(buildArgs.config) ? buildArgs.config : join(process.cwd(), buildArgs.config)); | ||||
| 
 | ||||
|   // register babel for config files
 | ||||
|   registerBabel({ | ||||
|     cwd, | ||||
|     only: customConfigPath ? CONFIG_FILES.concat(customConfigPath) : CONFIG_FILES, | ||||
|   }); | ||||
| 
 | ||||
|   const pkgName = (typeof pkg === 'string' ? pkg : pkg?.name) || 'unknown'; | ||||
| 
 | ||||
|   function log(msg, ...args) { | ||||
|     console.log(`${pkg ? `${randomColor(`${pkgName}`)}: ` : ''}${msg}`, ...args); | ||||
|   } | ||||
| 
 | ||||
|   // Get user config
 | ||||
|   const bundleOptsArray = getBundleOpts(opts); | ||||
|   const isPlugin = isPluginPackage(pkgName); | ||||
| 
 | ||||
|   // Clean dist
 | ||||
|   if (clean && !isPlugin) { | ||||
|     log(chalk.gray(`Clean dist directory`)); | ||||
|     rimraf.sync(join(cwd, 'dist')); | ||||
|   } | ||||
| 
 | ||||
|   for (const bundleOpts of bundleOptsArray) { | ||||
|     validateBundleOpts(bundleOpts, { cwd, rootPath }); | ||||
| 
 | ||||
|     // Build umd
 | ||||
|     if (bundleOpts.umd) { | ||||
|       log(`Build umd`); | ||||
|       await rollup({ | ||||
|         cwd, | ||||
|         rootPath, | ||||
|         log, | ||||
|         type: 'umd', | ||||
|         entry: bundleOpts.entry, | ||||
|         watch, | ||||
|         dispose, | ||||
|         bundleOpts, | ||||
|       }); | ||||
|     } | ||||
| 
 | ||||
|     // Build cjs
 | ||||
|     if (bundleOpts.cjs) { | ||||
|       const cjs = bundleOpts.cjs as IBundleTypeOutput; | ||||
|       log(`Build ${isPlugin ? 'd.ts' : 'cjs'} with ${cjs.type}`); | ||||
|       if (cjs.type === 'babel') { | ||||
|         await babel({ cwd, rootPath, watch, dispose, isPlugin, type: 'cjs', log, bundleOpts }); | ||||
|         if (isPlugin) { | ||||
|           log(cwd); | ||||
|           deleteJsFiles(cwd, log); | ||||
|           await buildPluginServer(cwd, log); | ||||
|           await buildPluginClient(cwd, log); | ||||
|           const buildFile = join(cwd, 'build.js'); | ||||
|           if (existsSync(buildFile)) { | ||||
|             log('build others'); | ||||
|             try { | ||||
|               await require(buildFile).run(log); | ||||
|             } catch (error) { | ||||
|               console.error(error); | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       } else { | ||||
|         await rollup({ | ||||
|           cwd, | ||||
|           rootPath, | ||||
|           log, | ||||
|           type: 'cjs', | ||||
|           entry: bundleOpts.entry, | ||||
|           watch, | ||||
|           dispose, | ||||
|           bundleOpts, | ||||
|         }); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     // Build esm
 | ||||
|     if (bundleOpts.esm) { | ||||
|       const esm = bundleOpts.esm as IEsm; | ||||
|       log(`Build esm with ${esm.type}`); | ||||
|       const importLibToEs = esm && esm.importLibToEs; | ||||
|       if (esm && esm.type === 'babel') { | ||||
|         await babel({ cwd, rootPath, watch, dispose, type: 'esm', importLibToEs, log, bundleOpts }); | ||||
|       } else { | ||||
|         await rollup({ | ||||
|           cwd, | ||||
|           rootPath, | ||||
|           log, | ||||
|           type: 'esm', | ||||
|           entry: bundleOpts.entry, | ||||
|           importLibToEs, | ||||
|           watch, | ||||
|           dispose, | ||||
|           bundleOpts, | ||||
|         }); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return dispose; | ||||
| } | ||||
| 
 | ||||
| function getPkgRelativePath(cwd, pkg) { | ||||
|   const basePath = cwd.split(sep).join('/') + '/packages/'; | ||||
|   const dir = pkg.contents.split(sep).join('/'); | ||||
|   return dir.substring(basePath.length); | ||||
| } | ||||
| 
 | ||||
| export async function buildForLerna(opts: IOpts) { | ||||
|   const { cwd, rootConfig = {}, buildArgs = {}, packages = [] } = opts; | ||||
| 
 | ||||
|   // register babel for config files
 | ||||
|   registerBabel({ | ||||
|     cwd, | ||||
|     only: CONFIG_FILES, | ||||
|   }); | ||||
| 
 | ||||
|   const userConfig = merge(getUserConfig({ cwd }), rootConfig, buildArgs); | ||||
| 
 | ||||
|   let pkgs = await getLernaPackages(cwd, userConfig.pkgFilter); | ||||
|   // support define pkgs in lerna
 | ||||
|   if (userConfig.pkgs) { | ||||
|     pkgs = pkgs.filter((pkg) => userConfig.pkgs.includes(getPkgRelativePath(cwd, pkg))); | ||||
|   } | ||||
|   const dispose: Dispose[] = []; | ||||
|   for (const pkg of pkgs) { | ||||
|     const pkgName = getPkgRelativePath(cwd, pkg); | ||||
|     if (userConfig.excludePkgs && userConfig.excludePkgs.includes(pkgName)) { | ||||
|       continue; | ||||
|     } | ||||
|     if (packages.length && !packages.includes(pkgName)) continue; | ||||
|     // build error when .DS_Store includes in packages root
 | ||||
|     const pkgPath = pkg.contents; | ||||
|     assert.ok(existsSync(join(pkgPath, 'package.json')), `package.json not found in packages/${pkg}`); | ||||
|     process.chdir(pkgPath); | ||||
|     dispose.push( | ||||
|       ...(await build( | ||||
|         { | ||||
|           // eslint-disable-line
 | ||||
|           ...opts, | ||||
|           buildArgs: opts.buildArgs, | ||||
|           rootConfig: userConfig, | ||||
|           cwd: pkgPath, | ||||
|           rootPath: cwd, | ||||
|         }, | ||||
|         { | ||||
|           pkg, | ||||
|         }, | ||||
|       )), | ||||
|     ); | ||||
|   } | ||||
|   return dispose; | ||||
| } | ||||
| 
 | ||||
| export default async function (opts: IOpts) { | ||||
|   const useLerna = existsSync(join(opts.cwd, 'lerna.json')); | ||||
|   const isLerna = useLerna && process.env.LERNA !== 'none'; | ||||
| 
 | ||||
|   const dispose = isLerna ? await buildForLerna(opts) : await build(opts); | ||||
|   return () => dispose.forEach((e) => e()); | ||||
| } | ||||
|  | ||||
							
								
								
									
										36
									
								
								packages/core/build/src/buildCjs.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								packages/core/build/src/buildCjs.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | ||||
| import { build } from 'tsup'; | ||||
| import fg from 'fast-glob'; | ||||
| import path from 'path'; | ||||
| import chalk from 'chalk'; | ||||
| import { globExcludeFiles, EsbuildSupportExts } from './constant'; | ||||
| import { PkgLog } from './utils'; | ||||
| 
 | ||||
| export function buildCjs(cwd: string, sourcemap: boolean = false, log: PkgLog) { | ||||
|   log('build cjs'); | ||||
| 
 | ||||
|   const entry = fg.globSync(['src/**', ...globExcludeFiles], { cwd, absolute: true }); | ||||
|   const outDir = path.join(cwd, 'lib'); | ||||
|   const otherExts = Array.from(new Set(entry.map((item) => path.extname(item)).filter((item) => !EsbuildSupportExts.includes(item)))); | ||||
|   if (otherExts.length) { | ||||
|     log('%s will not be processed, only be copied to the lib directory.', chalk.yellow(otherExts.join(','))); | ||||
|   } | ||||
| 
 | ||||
|   return build({ | ||||
|     entry, | ||||
|     splitting: false, | ||||
|     clean: true, | ||||
|     bundle: false, | ||||
|     silent: true, | ||||
|     sourcemap, | ||||
|     treeshake: false, | ||||
|     target: 'node16', | ||||
|     keepNames: true, | ||||
|     outDir, | ||||
|     loader: { | ||||
|       ...otherExts.reduce((prev, cur) => ({ ...prev, [cur]: 'copy' }), {}), | ||||
|       '.json': 'copy', | ||||
|     }, | ||||
|     format: 'cjs', | ||||
|     skipNodeModulesBundle: true, | ||||
|   }); | ||||
| } | ||||
							
								
								
									
										71
									
								
								packages/core/build/src/buildClient.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								packages/core/build/src/buildClient.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,71 @@ | ||||
| import path from 'path'; | ||||
| import fg from 'fast-glob'; | ||||
| import { build as viteBuild } from 'vite'; | ||||
| import { build as tsupBuild } from 'tsup'; | ||||
| import { libInjectCss } from 'vite-plugin-lib-inject-css'; | ||||
| import react from '@vitejs/plugin-react'; | ||||
| import { PkgLog } from './utils'; | ||||
| import { globExcludeFiles } from './constant'; | ||||
| 
 | ||||
| export async function buildClient(cwd: string, sourcemap: boolean = false, log: PkgLog) { | ||||
|   log('build client'); | ||||
| 
 | ||||
|   await Promise.all([buildLib(cwd, sourcemap, 'cjs'), buildLib(cwd, sourcemap, 'es')]); | ||||
|   await buildLocale(cwd); | ||||
| } | ||||
| 
 | ||||
| export function buildLib(cwd: string, sourcemap: boolean, format: 'cjs' | 'es') { | ||||
|   const outDir = path.resolve(cwd, format === 'cjs' ? 'lib' : 'es'); | ||||
|   const entry = path.join(cwd, 'src/index.ts').replaceAll(/\\/g, '/'); | ||||
|   const cwdWin = cwd.replaceAll(/\\/g, '/'); | ||||
|   const cwdUnix = cwd.replaceAll(/\//g, '\\'); | ||||
| 
 | ||||
|   return viteBuild({ | ||||
|     mode: 'production', | ||||
|     define: { | ||||
|       'process.env.NODE_ENV': JSON.stringify('production'), | ||||
|     }, | ||||
|     build: { | ||||
|       minify: false, | ||||
|       outDir, | ||||
|       cssCodeSplit: true, | ||||
|       emptyOutDir: true, | ||||
|       sourcemap, | ||||
|       lib: { | ||||
|         entry, | ||||
|         formats: [format], | ||||
|         fileName: 'index', | ||||
|       }, | ||||
|       target: ['es2015', 'edge88', 'firefox78', 'chrome87', 'safari14'], | ||||
|       rollupOptions: { | ||||
|         cache: true, | ||||
|         treeshake: true, | ||||
|         external(id) { | ||||
|           if (id.startsWith('.') || id.startsWith(cwdUnix) || id.startsWith(cwdWin)) { | ||||
|             return false; | ||||
|           } | ||||
|           return true; | ||||
|         }, | ||||
|       }, | ||||
|     }, | ||||
|     plugins: [react(), libInjectCss()], | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| export function buildLocale(cwd: string) { | ||||
|   const entry = fg.globSync(['src/locale/**', ...globExcludeFiles], { cwd, absolute: true }); | ||||
|   const outDir = path.resolve(cwd, 'lib', 'locale'); | ||||
|   return tsupBuild({ | ||||
|     entry, | ||||
|     splitting: false, | ||||
|     clean: false, | ||||
|     bundle: false, | ||||
|     silent: true, | ||||
|     treeshake: false, | ||||
|     target: 'node16', | ||||
|     keepNames: true, | ||||
|     outDir, | ||||
|     format: 'cjs', | ||||
|     skipNodeModulesBundle: true, | ||||
|   }); | ||||
| } | ||||
							
								
								
									
										33
									
								
								packages/core/build/src/buildDeclaration.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								packages/core/build/src/buildDeclaration.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | ||||
| import gulp from 'gulp'; | ||||
| import path from 'path'; | ||||
| import fs from 'fs'; | ||||
| import gulpTs from 'gulp-typescript'; | ||||
| import { ROOT_PATH } from './constant'; | ||||
| 
 | ||||
| export const buildDeclaration = (cwd: string, targetDir: string) => { | ||||
|   return new Promise((resolve, reject) => { | ||||
|     const srcPath = path.join(cwd, 'src'); | ||||
|     const targetPath = path.join(cwd, targetDir); | ||||
| 
 | ||||
|     const tsConfig = gulpTs.createProject(path.join(ROOT_PATH, 'tsconfig.json')); | ||||
|     delete tsConfig.config.compilerOptions.paths; | ||||
|     const patterns = [ | ||||
|       path.join(srcPath, '**/*.{ts,tsx}'), | ||||
|       `!${path.join(srcPath, '**/fixtures{,/**}')}`, | ||||
|       `!${path.join(srcPath, '**/demos{,/**}')}`, | ||||
|       `!${path.join(srcPath, '**/__test__{,/**}')}`, | ||||
|       `!${path.join(srcPath, '**/__tests__{,/**}')}`, | ||||
|       `!${path.join(srcPath, '**/*.mdx')}`, | ||||
|       `!${path.join(srcPath, '**/*.md')}`, | ||||
|       `!${path.join(srcPath, '**/*.+(test|e2e|spec).+(js|jsx|ts|tsx)')}`, | ||||
|       `!${path.join(srcPath, '**/tsconfig{,.*}.json')}`, | ||||
|       `!${path.join(srcPath, '.umi{,-production,-test}{,/**}')}`, | ||||
|     ]; | ||||
|     gulp | ||||
|       .src(patterns, { base: srcPath, allowEmpty: true }) | ||||
|       .pipe(gulpTs(tsConfig.config.compilerOptions)) | ||||
|       .dts.pipe(gulp.dest(targetPath)) | ||||
|       .on('end', resolve) | ||||
|       .on('error', reject); | ||||
|   }); | ||||
| }; | ||||
| @ -1,26 +1,30 @@ | ||||
| import ncc from '@vercel/ncc'; | ||||
| import react from '@vitejs/plugin-react'; | ||||
| import chalk from 'chalk'; | ||||
| import fg from 'fast-glob'; | ||||
| import fs from 'fs-extra'; | ||||
| import chalk from 'chalk'; | ||||
| import ncc from '@vercel/ncc'; | ||||
| import path from 'path'; | ||||
| import react from '@vitejs/plugin-react'; | ||||
| import { build as tsupBuild } from 'tsup'; | ||||
| import { build as viteBuild } from 'vite'; | ||||
| import fg from 'fast-glob'; | ||||
| import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js'; | ||||
| import { transformAsync } from '@babel/core'; | ||||
| 
 | ||||
| import { | ||||
|   buildCheck, | ||||
|   formatFileSize, | ||||
|   checkFileSize, | ||||
|   checkRequire, | ||||
|   getExcludePackages, | ||||
|   getFileSize, | ||||
|   getIncludePackages, | ||||
|   getPackageJson, | ||||
|   getPackagesFromFiles, | ||||
|   getSourcePackages, | ||||
| } from './utils/buildPluginUtils'; | ||||
| import { getDepsConfig } from './utils/getDepsConfig'; | ||||
| import { EsbuildSupportExts, globExcludeFiles } from './constant'; | ||||
| import { PkgLog, getPackageJson } from './utils'; | ||||
| 
 | ||||
| const serverGlobalFiles: string[] = ['src/**', '!src/**/__tests__', '!src/client/**']; | ||||
| 
 | ||||
| const clientGlobalFiles: string[] = ['src/client/**', '!src/**/__tests__']; | ||||
| const serverGlobalFiles: string[] = ['src/**', '!src/client/**', ...globExcludeFiles]; | ||||
| const clientGlobalFiles: string[] = ['src/**', '!src/server/**', ...globExcludeFiles]; | ||||
| const dynamicImportRegexp = /import\((["'])(.*?)\1\)/g; | ||||
| 
 | ||||
| const external = [ | ||||
|   // nocobase
 | ||||
| @ -116,17 +120,14 @@ const external = [ | ||||
|   'ahooks', | ||||
|   'lodash', | ||||
|   'china-division', | ||||
|   'cronstrue', | ||||
| ]; | ||||
| const pluginPrefix = ( | ||||
|   process.env.PLUGIN_PACKAGE_PREFIX || '@nocobase/plugin-,@nocobase/preset-,@nocobase/plugin-pro-' | ||||
| ).split(','); | ||||
| 
 | ||||
| type Log = (msg: string, ...args: any) => void; | ||||
| 
 | ||||
| const target_dir = 'dist'; | ||||
| 
 | ||||
| export function deleteJsFiles(cwd: string, log: Log) { | ||||
| export function deleteJsFiles(cwd: string, log: PkgLog) { | ||||
|   log('delete babel js files'); | ||||
|   const jsFiles = fg.globSync(['**/*', '!**/*.d.ts', '!node_modules'], { | ||||
|     cwd: path.join(cwd, target_dir), | ||||
| @ -137,23 +138,24 @@ export function deleteJsFiles(cwd: string, log: Log) { | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| export async function buildServerDeps(cwd: string, serverFiles: string[], log: Log) { | ||||
|   log('build server dependencies'); | ||||
| export async function buildServerDeps(cwd: string, serverFiles: string[], log: PkgLog) { | ||||
|   log('build plugin server dependencies'); | ||||
|   const outDir = path.join(cwd, target_dir, 'node_modules'); | ||||
|   const sourcePackages = getSourcePackages(serverFiles); | ||||
|   const serverFileSource = serverFiles.map((item) => fs.readFileSync(item, 'utf-8')); | ||||
|   const sourcePackages = getSourcePackages(serverFileSource); | ||||
|   const includePackages = getIncludePackages(sourcePackages, external, pluginPrefix); | ||||
|   const excludePackages = getExcludePackages(sourcePackages, external, pluginPrefix); | ||||
| 
 | ||||
|   let tips = []; | ||||
|   if (includePackages.length) { | ||||
|     tips.push( | ||||
|       `These packages ${chalk.yellow(includePackages.join(', '))} will be ${chalk.bold( | ||||
|       `These packages ${chalk.yellow(includePackages.join(', '))} will be ${chalk.italic( | ||||
|         'bundled', | ||||
|       )} to dist/node_modules.`,
 | ||||
|     ); | ||||
|   } | ||||
|   if (excludePackages.length) { | ||||
|     tips.push(`These packages ${chalk.yellow(excludePackages.join(', '))} will be ${chalk.bold('exclude')}.`); | ||||
|     tips.push(`These packages ${chalk.yellow(excludePackages.join(', '))} will be ${chalk.italic('exclude')}.`); | ||||
|   } | ||||
|   tips.push(`For more information, please refer to: ${chalk.blue('https://docs.nocobase.com/development/deps')}.`); | ||||
|   log(tips.join(' ')); | ||||
| @ -228,11 +230,15 @@ export async function buildServerDeps(cwd: string, serverFiles: string[], log: L | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export async function buildPluginServer(cwd: string, log: Log) { | ||||
|   log('build server source'); | ||||
| export async function buildPluginServer(cwd: string, sourcemap: boolean, log: PkgLog) { | ||||
|   log('build plugin server source'); | ||||
|   const packageJson = getPackageJson(cwd); | ||||
|   const serverFiles = fg.globSync(serverGlobalFiles, { cwd, absolute: true }); | ||||
|   buildCheck({ cwd, packageJson, entry: 'server', files: serverFiles, log }); | ||||
|   const otherExts = Array.from(new Set(serverFiles.map((item) => path.extname(item)).filter((item) => !EsbuildSupportExts.includes(item)))); | ||||
|   if (otherExts.length) { | ||||
|     log('%s will not be processed, only be copied to the dist directory.', chalk.yellow(otherExts.join(','))); | ||||
|   } | ||||
| 
 | ||||
|   await tsupBuild({ | ||||
|     entry: serverFiles, | ||||
| @ -240,26 +246,73 @@ export async function buildPluginServer(cwd: string, log: Log) { | ||||
|     clean: false, | ||||
|     bundle: false, | ||||
|     silent: true, | ||||
|     treeshake: true, | ||||
|     treeshake: false, | ||||
|     target: 'node16', | ||||
|     sourcemap, | ||||
|     outDir: path.join(cwd, target_dir), | ||||
|     format: 'cjs', | ||||
|     skipNodeModulesBundle: true, | ||||
|     loader: { | ||||
|       ...otherExts.reduce((prev, cur) => ({ ...prev, [cur]: 'copy' }), {}), | ||||
|       '.json': 'copy', | ||||
|     }, | ||||
|   }); | ||||
| 
 | ||||
|   await buildServerDeps(cwd, serverFiles, log); | ||||
| } | ||||
| 
 | ||||
| export function buildPluginClient(cwd: string, log: Log) { | ||||
|   log('build client'); | ||||
| export function transformClientFilesToAmd(outDir: string, outputFileName: string, packageName: string, log: PkgLog) { | ||||
|   const files = fs.readdirSync(outDir); | ||||
| 
 | ||||
|   return Promise.all(files.map(async file => { | ||||
|     const filePath = path.join(outDir, file); | ||||
| 
 | ||||
|     // 只编译 JavaScript 文件
 | ||||
|     if (path.extname(filePath) === '.mjs' || path.extname(filePath) === '.js') { | ||||
|       let fileContent = fs.readFileSync(filePath, 'utf-8'); | ||||
| 
 | ||||
|       // import('./dayjs.mjs') => import(window.staticBaseUrl + '/@nocobase/plugin-acl/dayjs.mjs?noExt')
 | ||||
|       if (file === outputFileName) { | ||||
|         fileContent = fileContent.replace(dynamicImportRegexp, (match, _1, dynamicImportPath) => { | ||||
|           let absolutePath = path.join(outDir, dynamicImportPath).replace(outDir, ''); | ||||
|           if (absolutePath.startsWith(path.sep)) { | ||||
|             absolutePath = absolutePath.slice(1); | ||||
|           } | ||||
|           return `import(window.staticBaseUrl + '/${packageName}/${absolutePath}?noExt')`; | ||||
|         }) | ||||
|       } | ||||
| 
 | ||||
|       const { code } = await transformAsync(fileContent, { | ||||
|         presets: [['@babel/preset-env', { | ||||
|           modules: 'amd', | ||||
|           targets: { | ||||
|             'edge': 88, | ||||
|             'firefox': 78, | ||||
|             'chrome': 87, | ||||
|             'safari': 14, | ||||
|           } | ||||
|         }]], | ||||
|         plugins: ['@babel/plugin-transform-modules-amd'], | ||||
|       }); | ||||
|       fs.writeFileSync(filePath, code, 'utf-8'); | ||||
|     } | ||||
|   })); | ||||
| } | ||||
| 
 | ||||
| export async function buildPluginClient(cwd: string, sourcemap: boolean, log: PkgLog) { | ||||
|   log('build plugin client'); | ||||
|   const packageJson = getPackageJson(cwd); | ||||
|   const clientFiles = fg.globSync(clientGlobalFiles, { cwd, absolute: true }); | ||||
|   const sourcePackages = getSourcePackages(clientFiles); | ||||
|   const clientFileSource = clientFiles.map((item) => fs.readFileSync(item, 'utf-8')); | ||||
|   const sourcePackages = getPackagesFromFiles(clientFileSource); | ||||
|   const excludePackages = getExcludePackages(sourcePackages, external, pluginPrefix); | ||||
| 
 | ||||
|   checkRequire(clientFiles, log); | ||||
|   buildCheck({ cwd, packageJson, entry: 'client', files: clientFiles, log }); | ||||
| 
 | ||||
|   const hasDynamicImport = false; | ||||
|   // const hasDynamicImport = clientFileSource.some((source) => {
 | ||||
|   //   return source.match(dynamicImportRegexp);
 | ||||
|   // });
 | ||||
|   const outDir = path.join(cwd, target_dir, 'client'); | ||||
| 
 | ||||
|   const globals = excludePackages.reduce<Record<string, string>>((prev, curr) => { | ||||
| @ -270,48 +323,63 @@ export function buildPluginClient(cwd: string, log: Log) { | ||||
|     return prev; | ||||
|   }, {}); | ||||
| 
 | ||||
|   const entry = fg.globSync('src/client/index.{ts,tsx,js,jsx}', { cwd }); | ||||
|   const entry = fg.globSync('src/client/index.{ts,tsx,js,jsx}', { absolute: true, cwd }); | ||||
|   const outputFileName = 'index.js'; | ||||
|   return viteBuild({ | ||||
|   await viteBuild({ | ||||
|     mode: 'production', | ||||
|     define: { | ||||
|       'process.env.NODE_ENV': JSON.stringify('production'), | ||||
|     }, | ||||
|     logLevel: 'warn', | ||||
|     build: { | ||||
|       minify: false, | ||||
|       minify: true, | ||||
|       outDir, | ||||
|       cssCodeSplit: false, | ||||
|       emptyOutDir: false, | ||||
|       emptyOutDir: true, | ||||
|       sourcemap, | ||||
|       lib: { | ||||
|         entry, | ||||
|         formats: ['umd'], | ||||
|         formats: [hasDynamicImport ? 'es' : 'umd'], | ||||
|         name: packageJson.name, | ||||
|         fileName: () => outputFileName, | ||||
|       }, | ||||
|       target: ['es2015', 'edge88', 'firefox78', 'chrome87', 'safari14'], | ||||
|       rollupOptions: { | ||||
|         cache: true, | ||||
|         external: Object.keys(globals), | ||||
|         external: [...Object.keys(globals), 'react', 'react/jsx-runtime'], | ||||
|         output: { | ||||
|           exports: 'named', | ||||
|           globals, | ||||
|           globals: { | ||||
|             react: 'React', | ||||
|             'react/jsx-runtime': 'jsxRuntime', | ||||
|             ...globals, | ||||
|           }, | ||||
|         }, | ||||
|       }, | ||||
|     }, | ||||
|     plugins: [ | ||||
|       react(), | ||||
|       cssInjectedByJsPlugin({ styleId: packageJson.name }), | ||||
|       { | ||||
|         name: 'check-file-size', | ||||
|         closeBundle() { | ||||
|           const file = path.join(outDir, outputFileName); | ||||
|           if (!fs.existsSync(file)) return; | ||||
|           const fileSize = getFileSize(path.join(outDir, outputFileName)); | ||||
|           if (fileSize > 1024 * 1024) { | ||||
|             log('The bundle file size exceeds 1MB %s. ', chalk.red(formatFileSize(fileSize))); | ||||
|           } | ||||
|         }, | ||||
|       }, | ||||
|     ], | ||||
|   }); | ||||
| 
 | ||||
|   checkFileSize(outDir, log); | ||||
| 
 | ||||
|   // if (hasDynamicImport) {
 | ||||
|   //   await transformClientFilesToAmd(outDir, outputFileName, packageJson.name, log);
 | ||||
|   // }
 | ||||
| } | ||||
| 
 | ||||
| export async function buildPlugin(cwd: string, sourcemap: boolean, log: PkgLog) { | ||||
|   await buildPluginClient(cwd, sourcemap, log); | ||||
|   await buildPluginServer(cwd, sourcemap, log); | ||||
|   const buildFile = path.join(cwd, 'build.js'); | ||||
|   if (fs.existsSync(buildFile)) { | ||||
|     log('build others'); | ||||
|     try { | ||||
|       await require(buildFile).run(log); | ||||
|     } catch (error) { | ||||
|       console.error(error); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
							
								
								
									
										46
									
								
								packages/core/build/src/constant.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								packages/core/build/src/constant.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | ||||
| import path from 'path'; | ||||
| import { Package } from '@lerna/package'; | ||||
| 
 | ||||
| export const globExcludeFiles = [ | ||||
|   '!src/**/__tests__', | ||||
|   '!src/**/__test__', | ||||
|   '!src/**/demos', | ||||
|   '!src/**/fixtures', | ||||
|   '!src/**/*.mdx', | ||||
|   '!src/**/*.md', | ||||
|   '!src/**/*.+(test|e2e|spec).+(js|jsx|ts|tsx)', | ||||
| ]; | ||||
| export const EsbuildSupportExts = [ | ||||
|   '.ts', | ||||
|   '.tsx', | ||||
|   '.js', | ||||
|   '.jsx', | ||||
|   '.json', | ||||
|   '.css', | ||||
|   '.less', | ||||
|   '.sass', | ||||
|   '.scss', | ||||
|   '.styl', | ||||
|   '.txt', | ||||
|   '.data', | ||||
| ]; | ||||
| export const ROOT_PATH = path.join(__dirname, '../../../../'); | ||||
| export const PACKAGES_PATH = path.join(ROOT_PATH, 'packages'); | ||||
| export const PLUGINS_DIR = [path.join(PACKAGES_PATH, 'plugins'), path.join(PACKAGES_PATH, 'samples')]; | ||||
| export const PRESETS_DIR = path.join(PACKAGES_PATH, 'presets'); | ||||
| export const getPluginPackages = (packages: Package[]) => | ||||
|   packages.filter((item) => PLUGINS_DIR.some((pluginDir) => item.location.startsWith(pluginDir))); | ||||
| export const getPresetsPackages = (packages: Package[]) => | ||||
|   packages.filter((item) => item.location.startsWith(PRESETS_DIR)); | ||||
| export const CORE_APP = path.join(PACKAGES_PATH, 'core/app'); | ||||
| export const CORE_CLIENT = path.join(PACKAGES_PATH, 'core/client'); | ||||
| export const CJS_EXCLUDE_PACKAGES = [ | ||||
|   path.join(PACKAGES_PATH, 'core/build'), | ||||
|   path.join(PACKAGES_PATH, 'core/cli'), | ||||
|   CORE_CLIENT, | ||||
| ]; | ||||
| export const getCjsPackages = (packages: Package[]) => | ||||
|   packages | ||||
|     .filter((item) => !PLUGINS_DIR.some((dir) => item.location.startsWith(dir))) | ||||
|     .filter((item) => !item.location.startsWith(PRESETS_DIR)) | ||||
|     .filter((item) => !CJS_EXCLUDE_PACKAGES.includes(item.location)); | ||||
| @ -1,33 +0,0 @@ | ||||
| // 参考:
 | ||||
| // https://github.com/umijs/umi/blob/2.x/packages/af-webpack/src/getWebpackConfig/es5ImcompatibleVersions.js
 | ||||
| import { dirname } from 'path'; | ||||
| import pkgUp from 'pkg-up'; | ||||
| import { satisfies } from 'semver'; | ||||
| 
 | ||||
| const pkgPathCache = {}; | ||||
| const pkgCache = {}; | ||||
| const { | ||||
|   config: { 'es5-imcompatible-versions': config }, | ||||
| } = require('es5-imcompatible-versions/package.json'); | ||||
| 
 | ||||
| export function getPkgPath(filePath: string) { | ||||
|   const dir = dirname(filePath); | ||||
|   if (dir in pkgPathCache) return pkgPathCache[dir]; | ||||
|   pkgPathCache[dir] = pkgUp.sync({ cwd: filePath }); | ||||
|   return pkgPathCache[dir]; | ||||
| } | ||||
| 
 | ||||
| export function shouldTransform(pkgPath: string) { | ||||
|   if (pkgPath in pkgCache) return pkgCache[pkgPath]; | ||||
|   const { name, version } = require(pkgPath); | ||||
|   pkgCache[pkgPath] = isMatch(name, version); | ||||
|   return pkgCache[pkgPath]; | ||||
| } | ||||
| 
 | ||||
| function isMatch(name, version) { | ||||
|   if (config[name]) { | ||||
|     return Object.keys(config[name]).some((sv) => satisfies(version, sv)); | ||||
|   } else { | ||||
|     return false; | ||||
|   } | ||||
| } | ||||
| @ -1,8 +0,0 @@ | ||||
| 
 | ||||
| export default { | ||||
|   esm: 'babel', | ||||
|   target: 'node', | ||||
|   browserFiles: [ | ||||
|     'src/browser.js', | ||||
|   ], | ||||
| } | ||||
| @ -1 +0,0 @@ | ||||
| var b = 'foo'; | ||||
| @ -1 +0,0 @@ | ||||
| const a = 'foo'; | ||||
| @ -1,2 +0,0 @@ | ||||
| 
 | ||||
| const b = 'foo'; | ||||
| @ -1,2 +0,0 @@ | ||||
| 
 | ||||
| const a = 'foo'; | ||||
| @ -1,8 +0,0 @@ | ||||
| 
 | ||||
| export default { | ||||
|   target: 'node', | ||||
|   cjs: { type: 'babel', lazy: true }, | ||||
|   browserFiles: [ | ||||
|     'src/foo.js', | ||||
|   ], | ||||
| }; | ||||
| @ -1,3 +0,0 @@ | ||||
| import bar from 'bar'; | ||||
| 
 | ||||
| bar(); | ||||
| @ -1,3 +0,0 @@ | ||||
| import bar from 'bar'; | ||||
| 
 | ||||
| bar(); | ||||
| @ -1,10 +0,0 @@ | ||||
| 
 | ||||
| export default { | ||||
|   esm: { type: 'babel' }, | ||||
|   extraBabelPresets: [ | ||||
|     require.resolve('./preset'), | ||||
|   ], | ||||
|   extraBabelPlugins: [ | ||||
|     require.resolve('./p2'), | ||||
|   ], | ||||
| }; | ||||
| @ -1,2 +0,0 @@ | ||||
| console.log("p1", "p2", 1); | ||||
| alert(2); | ||||
| @ -1,20 +0,0 @@ | ||||
| 
 | ||||
| module.exports = function ({ types: t }) { | ||||
|   function isConsoleLog(node) { | ||||
|     const { callee, callee: { object, property } } = node; | ||||
|     return t.isMemberExpression(callee) | ||||
|       && t.isIdentifier(object) && object.name === 'console' | ||||
|       && t.isIdentifier(property) && property.name === 'log'; | ||||
|   } | ||||
| 
 | ||||
|   return { | ||||
|     visitor: { | ||||
|       CallExpression(path, state) { | ||||
|         const { node, node: { callee, callee: { object, property } } } = path; | ||||
|         if (isConsoleLog(node)) { | ||||
|           node.arguments.unshift(t.stringLiteral('p1')); | ||||
|         } | ||||
|       }, | ||||
|     }, | ||||
|   }; | ||||
| } | ||||
| @ -1,20 +0,0 @@ | ||||
| 
 | ||||
| module.exports = function ({ types: t }) { | ||||
|   function isConsoleLog(node) { | ||||
|     const { callee, callee: { object, property } } = node; | ||||
|     return t.isMemberExpression(callee) | ||||
|       && t.isIdentifier(object) && object.name === 'console' | ||||
|       && t.isIdentifier(property) && property.name === 'log'; | ||||
|   } | ||||
| 
 | ||||
|   return { | ||||
|     visitor: { | ||||
|       CallExpression(path, state) { | ||||
|         const { node, node: { callee, callee: { object, property } } } = path; | ||||
|         if (isConsoleLog(node)) { | ||||
|           node.arguments.unshift(t.stringLiteral('p2')); | ||||
|         } | ||||
|       }, | ||||
|     }, | ||||
|   }; | ||||
| } | ||||
| @ -1,8 +0,0 @@ | ||||
| 
 | ||||
| module.exports = function () { | ||||
|   return { | ||||
|     plugins: [ | ||||
|       require.resolve('./p1'), | ||||
|     ], | ||||
|   }; | ||||
| } | ||||
| @ -1,3 +0,0 @@ | ||||
| 
 | ||||
| console.log(1); | ||||
| alert(2); | ||||
| @ -1,5 +0,0 @@ | ||||
| 
 | ||||
| export default { | ||||
|   cjs: { type: 'babel' }, | ||||
|   esm: { type: 'babel', importLibToEs: true }, | ||||
| }; | ||||
| @ -1,2 +0,0 @@ | ||||
| import foo from "foo/es/foo"; | ||||
| console.log(foo()); | ||||
| @ -1,3 +0,0 @@ | ||||
| import foo from 'foo/lib/foo'; | ||||
| 
 | ||||
| console.log(foo()); | ||||
| @ -1,6 +0,0 @@ | ||||
| 
 | ||||
| export default { | ||||
|   cjs: { type: 'babel' }, | ||||
|   esm: { type: 'babel' }, | ||||
|   lessInBabelMode: false, | ||||
| }; | ||||
| @ -1,6 +0,0 @@ | ||||
| 
 | ||||
| import "./index.less"; | ||||
| import "./foo.module.less"; | ||||
| export default function () { | ||||
|   return 'foo'; | ||||
| } | ||||
| @ -1,3 +0,0 @@ | ||||
| .foo { | ||||
|   color: green; | ||||
| } | ||||
| @ -1,6 +0,0 @@ | ||||
| 
 | ||||
| @link-color: green; | ||||
| 
 | ||||
| .foo { | ||||
|   color: @link-color; | ||||
| } | ||||
| @ -1,6 +0,0 @@ | ||||
| import "./index.less"; | ||||
| import "./foo.module.less"; | ||||
| 
 | ||||
| export default function () { | ||||
|   return 'foo'; | ||||
| } | ||||
| @ -1,3 +0,0 @@ | ||||
| .foo { | ||||
|   color: green; | ||||
| } | ||||
| @ -1,6 +0,0 @@ | ||||
| 
 | ||||
| @link-color: green; | ||||
| 
 | ||||
| .foo { | ||||
|   color: @link-color; | ||||
| } | ||||
| @ -1,6 +0,0 @@ | ||||
| 
 | ||||
| export default { | ||||
|   cjs: { type: 'babel' }, | ||||
|   esm: { type: 'babel' }, | ||||
|   lessInBabelMode: true, | ||||
| }; | ||||
| @ -1,6 +0,0 @@ | ||||
| 
 | ||||
| import "./index.css"; | ||||
| import "./foo.module.css"; | ||||
| export default function () { | ||||
|   return 'foo'; | ||||
| } | ||||
| @ -1,3 +0,0 @@ | ||||
| .foo { | ||||
|   color: green; | ||||
| } | ||||
| @ -1,3 +0,0 @@ | ||||
| .foo { | ||||
|   color: green; | ||||
| } | ||||
| @ -1,6 +0,0 @@ | ||||
| import "./index.less"; | ||||
| import "./foo.module.less"; | ||||
| 
 | ||||
| export default function () { | ||||
|   return 'foo'; | ||||
| } | ||||
| @ -1,3 +0,0 @@ | ||||
| .foo { | ||||
|   color: green; | ||||
| } | ||||
| @ -1,6 +0,0 @@ | ||||
| 
 | ||||
| @link-color: green; | ||||
| 
 | ||||
| .foo { | ||||
|   color: @link-color; | ||||
| } | ||||
| @ -1,8 +0,0 @@ | ||||
| 
 | ||||
| export default { | ||||
|   esm: 'babel', | ||||
|   target: 'browser', | ||||
|   nodeFiles: [ | ||||
|     'src/node.js', | ||||
|   ], | ||||
| } | ||||
| @ -1 +0,0 @@ | ||||
| var b = 'foo'; | ||||
| @ -1 +0,0 @@ | ||||
| const a = 'foo'; | ||||
| @ -1,2 +0,0 @@ | ||||
| 
 | ||||
| const b = 'foo'; | ||||
| @ -1,2 +0,0 @@ | ||||
| 
 | ||||
| const a = 'foo'; | ||||
| @ -1,5 +0,0 @@ | ||||
| 
 | ||||
| export default { | ||||
|   esm: 'babel', | ||||
|   target: 'node', | ||||
| } | ||||
| @ -1 +0,0 @@ | ||||
| declare const b = "foo"; | ||||
| @ -1 +0,0 @@ | ||||
| var b = 'foo'; | ||||
| @ -1 +0,0 @@ | ||||
| var b = 'foo'; | ||||
| @ -1 +0,0 @@ | ||||
| const a = 'foo'; | ||||
| @ -1,2 +0,0 @@ | ||||
| 
 | ||||
| const b = 'foo'; | ||||
| @ -1,2 +0,0 @@ | ||||
| 
 | ||||
| const b = 'foo'; | ||||
| @ -1,2 +0,0 @@ | ||||
| 
 | ||||
| const a = 'foo'; | ||||
| @ -1,9 +0,0 @@ | ||||
| { | ||||
|   "compilerOptions": { | ||||
|     "target": "esnext", | ||||
|     "moduleResolution": "node", | ||||
|     "jsx": "preserve", | ||||
|     "esModuleInterop": true, | ||||
|     "declaration": true | ||||
|   } | ||||
| } | ||||
| @ -1,5 +0,0 @@ | ||||
| 
 | ||||
| export default { | ||||
|   cjs: { type: 'babel' }, | ||||
|   esm: { type: 'babel' }, | ||||
| }; | ||||
| @ -1,3 +0,0 @@ | ||||
| export default function () { | ||||
|   return 'foo'; | ||||
| } | ||||
| @ -1,3 +0,0 @@ | ||||
| import 'bar'; | ||||
| import foo from './foo'; | ||||
| console.log(foo()); | ||||
| @ -1 +0,0 @@ | ||||
| export default {}; | ||||
| @ -1 +0,0 @@ | ||||
| export default {}; | ||||
| @ -1 +0,0 @@ | ||||
| # bar | ||||
| @ -1 +0,0 @@ | ||||
| # bar | ||||
| @ -1,3 +0,0 @@ | ||||
| export default function() { | ||||
|   return "foo"; | ||||
| } | ||||
| @ -1 +0,0 @@ | ||||
| {} | ||||
| @ -1,4 +0,0 @@ | ||||
| 
 | ||||
| export default function () { | ||||
|   return 'foo'; | ||||
| } | ||||
| @ -1,4 +0,0 @@ | ||||
| import 'bar'; | ||||
| import foo from './foo'; | ||||
| 
 | ||||
| console.log(foo()); | ||||
| @ -1,6 +0,0 @@ | ||||
| 
 | ||||
| export default { | ||||
|   runtimeHelpers: true, | ||||
|   esm: { type: 'babel' }, | ||||
|   cjs: { type: 'babel' }, | ||||
| } | ||||
| @ -1,21 +0,0 @@ | ||||
| import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2"; | ||||
| import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck"; | ||||
| import _createClass from "@babel/runtime/helpers/esm/createClass"; | ||||
| 
 | ||||
| var A = /*#__PURE__*/function () { | ||||
|   function A() { | ||||
|     _classCallCheck(this, A); | ||||
|   } | ||||
| 
 | ||||
|   _createClass(A, [{ | ||||
|     key: "foo", | ||||
|     value: function foo() {} | ||||
|   }]); | ||||
| 
 | ||||
|   return A; | ||||
| }(); | ||||
| 
 | ||||
| new A().foo(); | ||||
| var a = {}; | ||||
| 
 | ||||
| var b = _objectSpread({}, a); | ||||
| @ -1,5 +0,0 @@ | ||||
| { | ||||
|   "dependencies": { | ||||
|     "@babel/runtime": "7.10.4" | ||||
|   } | ||||
| } | ||||
| @ -1,9 +0,0 @@ | ||||
| 
 | ||||
| class A { | ||||
|   foo() {} | ||||
| } | ||||
| 
 | ||||
| (new A()).foo(); | ||||
| 
 | ||||
| const a = {}; | ||||
| const b = {...a}; | ||||
| @ -1,4 +0,0 @@ | ||||
| 
 | ||||
| export default { | ||||
|   esm: { type: 'rollup' }, | ||||
| }; | ||||
| @ -1,84 +0,0 @@ | ||||
| import React from 'react'; | ||||
| 
 | ||||
| function _classCallCheck(instance, Constructor) { | ||||
|   if (!(instance instanceof Constructor)) { | ||||
|     throw new TypeError("Cannot call a class as a function"); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function _objectWithoutPropertiesLoose(source, excluded) { | ||||
|   if (source == null) return {}; | ||||
|   var target = {}; | ||||
|   var sourceKeys = Object.keys(source); | ||||
|   var key, i; | ||||
| 
 | ||||
|   for (i = 0; i < sourceKeys.length; i++) { | ||||
|     key = sourceKeys[i]; | ||||
|     if (excluded.indexOf(key) >= 0) continue; | ||||
|     target[key] = source[key]; | ||||
|   } | ||||
| 
 | ||||
|   return target; | ||||
| } | ||||
| 
 | ||||
| function _objectWithoutProperties(source, excluded) { | ||||
|   if (source == null) return {}; | ||||
| 
 | ||||
|   var target = _objectWithoutPropertiesLoose(source, excluded); | ||||
| 
 | ||||
|   var key, i; | ||||
| 
 | ||||
|   if (Object.getOwnPropertySymbols) { | ||||
|     var sourceSymbolKeys = Object.getOwnPropertySymbols(source); | ||||
| 
 | ||||
|     for (i = 0; i < sourceSymbolKeys.length; i++) { | ||||
|       key = sourceSymbolKeys[i]; | ||||
|       if (excluded.indexOf(key) >= 0) continue; | ||||
|       if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; | ||||
|       target[key] = source[key]; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return target; | ||||
| } | ||||
| 
 | ||||
| function a () { | ||||
|   alert('a'); | ||||
| } | ||||
| 
 | ||||
| function b1() { | ||||
|   alert('b1'); | ||||
| } | ||||
| function b2() { | ||||
|   alert('b2'); | ||||
| } | ||||
| 
 | ||||
| var b = /*#__PURE__*/Object.freeze({ | ||||
|   __proto__: null, | ||||
|   b1: b1, | ||||
|   b2: b2 | ||||
| }); | ||||
| 
 | ||||
| var _class; | ||||
| // babel-plugin-react-require
 | ||||
| var Foo = function Foo() { | ||||
|   return /*#__PURE__*/React.createElement("div", null); | ||||
| }; // Don't support multiple chunks for now
 | ||||
| // @babel/plugin-syntax-dynamic-import
 | ||||
| // import('./a');
 | ||||
| // object-rest-spread
 | ||||
| 
 | ||||
| var _bar = bar, | ||||
|     foo = _bar.foo, | ||||
|     z = _objectWithoutProperties(_bar, ["foo"]); | ||||
| 
 | ||||
| console.log(z); // @babel/plugin-proposal-decorators + class
 | ||||
| 
 | ||||
| var A = foo(_class = function A() { | ||||
|   _classCallCheck(this, A); | ||||
| }) || _class; // export default from
 | ||||
| 
 | ||||
| var a$1 = x > 10 ? 'big' : 'small'; | ||||
| console.log(a$1); // export namespace from
 | ||||
| 
 | ||||
| export { A, Foo, a, b }; | ||||
| @ -1,5 +0,0 @@ | ||||
| { | ||||
|   "dependencies": { | ||||
|     "react": "^18.0.0" | ||||
|   } | ||||
| } | ||||
| @ -1,4 +0,0 @@ | ||||
| 
 | ||||
| export default function () { | ||||
|   alert('a'); | ||||
| } | ||||
| @ -1,8 +0,0 @@ | ||||
| 
 | ||||
| export function b1() { | ||||
|   alert('b1'); | ||||
| } | ||||
| 
 | ||||
| export function b2() { | ||||
|   alert('b2'); | ||||
| } | ||||
| @ -1,32 +0,0 @@ | ||||
| 
 | ||||
| // babel-plugin-react-require
 | ||||
| export const Foo = () => <div />; | ||||
| 
 | ||||
| // Don't support multiple chunks for now
 | ||||
| // @babel/plugin-syntax-dynamic-import
 | ||||
| // import('./a');
 | ||||
| 
 | ||||
| // object-rest-spread
 | ||||
| const { foo, ...z } = bar; | ||||
| console.log(z); | ||||
| 
 | ||||
| // @babel/plugin-proposal-decorators + class
 | ||||
| @foo | ||||
| export class A {} | ||||
| 
 | ||||
| // export default from
 | ||||
| export a from './a'; | ||||
| 
 | ||||
| // do expression
 | ||||
| let a = do { | ||||
|   if(x > 10) { | ||||
|     'big'; | ||||
|   } else { | ||||
|     'small'; | ||||
|   } | ||||
| }; | ||||
| console.log(a); | ||||
| 
 | ||||
| // export namespace from
 | ||||
| export * as b from './b'; | ||||
| 
 | ||||
| @ -1,4 +0,0 @@ | ||||
| export default { | ||||
|   cjs: { type: 'babel' }, | ||||
|   esm: { type: 'babel' }, | ||||
| }; | ||||
| @ -1,2 +0,0 @@ | ||||
| export declare const optionalChaining: string; | ||||
| export declare const nullishCoalescing: string | boolean; | ||||
| @ -1,6 +0,0 @@ | ||||
| var _foo$test; | ||||
| 
 | ||||
| var foo = {}; | ||||
| export var optionalChaining = foo === null || foo === void 0 ? void 0 : (_foo$test = foo.test) === null || _foo$test === void 0 ? void 0 : _foo$test.abc; | ||||
| var bar = false; | ||||
| export var nullishCoalescing = bar !== null && bar !== void 0 ? bar : 'default'; | ||||
| @ -1,11 +0,0 @@ | ||||
| type Foo = { | ||||
|   test?: { | ||||
|     abc?: string; | ||||
|   } | ||||
| } | ||||
| const foo: Foo = {}; | ||||
| 
 | ||||
| export const optionalChaining = foo?.test?.abc; | ||||
| 
 | ||||
| const bar = false; | ||||
| export const nullishCoalescing = bar ?? 'default'; | ||||
| @ -1,6 +0,0 @@ | ||||
| 
 | ||||
| export default { | ||||
|   cjs: { type: 'babel' }, | ||||
|   esm: { type: 'babel' }, | ||||
|   disableTypeCheck: true, | ||||
| }; | ||||
| @ -1,3 +0,0 @@ | ||||
| export default function foo(opts) { | ||||
|   return opts.foo ? 'foo' : 'bar'; | ||||
| } | ||||
| @ -1,7 +0,0 @@ | ||||
| interface IOpts { | ||||
|   foo: boolean; | ||||
| } | ||||
| 
 | ||||
| export default function foo(opts: IOpts): string { | ||||
|   return opts.foo ? 'foo' : 'bar'; | ||||
| } | ||||
| @ -1,8 +0,0 @@ | ||||
| { | ||||
|   "compilerOptions": { | ||||
|     "target": "esnext", | ||||
|     "moduleResolution": "node", | ||||
|     "jsx": "preserve", | ||||
|     "esModuleInterop": true | ||||
|   } | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue
	
	Block a user