nocobase/packages/core/devtools/umiConfig.js
jack zhang 705b7449f0
feat: new plugin manager, supports adding plugins through UI (#2430)
* refactor: plugin manager page

* fix: bug

* feat: addByNpm api

* fix: improve the addByNpm

* feat: improve applicationPlugins:list api

* fix: re-download npm package when restart app

* fix: plugin delete api

* feat: plugin detail api

* feat: zipUrl add api

* fix: upload api bug

* fix: plugin detail info

* feat: upgrade api

* fix: upload api

* feat: handle plugin load error

* feat: support authToken

* feat: muti lang

* fix: build error

* fix: self review

* Update plugin-manager.ts

* fix: bug

* fix: bug

* fix: bug

* fix: bug

* fix: bug

* fix: bugs

* fix: detail click and remove isOfficial

* fix: upgrade no refresh

* fix: file size and type check

* fix: bug

* fix: upgrade error

* fix: bug

* fix: bug

* fix: plugin card layout

* fix: handling exceptional cases

* fix: tgz file support

* fix: macos compress file

* fix: bug

* fix: bug

* fix: bug

* fix: bug

* fix: add upgrade npm type

* fix: bugs

* fix: bug

* fix: change plugins static expose url

* fix: api prefix

* fix: bug

* fix: add nginx `/static/plugin/` path

* fix: bugs and pr docker build no dts

* fix: bug

* fix: build tools bug

* fix: improve code

* fix: build bug

* feat: improve plugin info

* fix: ui bug

* fix: plugin document bug

* feat: improve code

* feat: improve code

* feat: process dev deps check

* feat: improve code

* feat: process.env.IS_DEV_CMD

* fix: do not delete the plugin package

* feat: plugin symlink

* fix: tsx watch --ignore=./storage/plugins/**

* fix: test error

* fix: improve code

* fix: improve code

* fix: emitStartedEvent

* fix: improve code

* fix: type error

* fix: test error

* test: console.log

* fix: createStoragePluginSymLink

* fix: clientStaticMiddleware rename to clientStaticUtils

* feat: build tools support plugins folder

* fix: 350px

* fix: error

* feat: client dev support plugin folder

* fix: clear cli options

* fix: typeError: Converting circular structure to JSON

* fix: plugin name

* chore: restart application after command

* feat: upgrade error & docs

* Update v14-changelog.md

* Update v14-changelog.md

* Update v14-changelog.md

* fix: gateway test

* refactor(plugin-workflow): add ready state for gracefully tearing down

* Revert "chore: restart application after command"

This reverts commit 5015274f8e.

* chore: stop application whe restart

* T 1218 change plugin folder (#2629)

* feat: change folder name

* feat: change `pm create` command

* feat:  revert plugin name change

* fix: delete samples

* feat: change plugins folder

* fix: pm create

* feat: update docs

* fix: link package error

* fix: docs

* fix: create command

* fix: pm add error

* fix: create  add build

* fix: pm creatre + add

* feat: add tar command

* fix: docs

* fix: bug

* fix: docs

---------

Co-authored-by: chenos <chenlinxh@gmail.com>

* feat: docs

* Update your-fisrt-plugin.md

* Update your-fisrt-plugin.md

* chore: application reload

* chore: test

* fix: pm add error

* chore: preset install skip exists plugin

* fix: createIfNotExists

---------

Co-authored-by: chenos <chenlinxh@gmail.com>
Co-authored-by: chareice <chareice@live.com>
Co-authored-by: Zhou <zhou.working@gmail.com>
Co-authored-by: mytharcher <mytharcher@gmail.com>
2023-09-12 22:39:23 +08:00

218 lines
6.7 KiB
JavaScript

const { existsSync } = require('fs');
const { resolve, sep } = require('path');
const packageJson = require('./package.json');
const fs = require('fs');
const glob = require('fast-glob');
const path = require('path');
console.log('VERSION: ', packageJson.version);
function getUmiConfig() {
const { APP_PORT, API_BASE_URL } = process.env;
const API_BASE_PATH = process.env.API_BASE_PATH || '/api/';
const PROXY_TARGET_URL = process.env.PROXY_TARGET_URL || `http://127.0.0.1:${APP_PORT}`;
const LOCAL_STORAGE_BASE_URL = '/storage/uploads/';
const STATIC_PATH = '/static/';
function getLocalStorageProxy() {
if (LOCAL_STORAGE_BASE_URL.startsWith('http')) {
return {};
}
return {
[LOCAL_STORAGE_BASE_URL]: {
target: PROXY_TARGET_URL,
changeOrigin: true,
},
[STATIC_PATH]: {
target: PROXY_TARGET_URL,
changeOrigin: true,
},
};
}
return {
alias: getPackagePaths().reduce((memo, item) => {
memo[item[0]] = item[1];
return memo;
}, {}),
define: {
'process.env.API_BASE_URL': API_BASE_URL || API_BASE_PATH,
'process.env.APP_ENV': process.env.APP_ENV,
'process.env.VERSION': packageJson.version,
'process.env.WEBSOCKET_URL': process.env.WEBSOCKET_URL,
},
// only proxy when using `umi dev`
// if the assets are built, will not proxy
proxy: {
[API_BASE_PATH]: {
target: PROXY_TARGET_URL,
changeOrigin: true,
pathRewrite: { [`^${API_BASE_PATH}`]: API_BASE_PATH },
},
// for local storage
...getLocalStorageProxy(),
},
};
}
function getNamespace() {
const content = fs.readFileSync(resolve(process.cwd(), 'package.json'), 'utf-8');
const json = JSON.parse(content);
return json.name;
}
function getTsconfigPaths() {
const content = fs.readFileSync(resolve(process.cwd(), 'tsconfig.json'), 'utf-8');
const json = JSON.parse(content);
return json.compilerOptions.paths;
}
function getPackagePaths() {
const paths = getTsconfigPaths();
const pkgs = [];
for (const key in paths) {
if (Object.hasOwnProperty.call(paths, key)) {
for (let dir of paths[key]) {
if (dir.includes('*')) {
const files = glob.sync(dir, { cwd: process.cwd(), onlyDirectories: true });
for (const file of files) {
const dirname = resolve(process.cwd(), file);
if (existsSync(dirname)) {
const re = new RegExp(dir.replace('*', '(.+)'));
const p = dirname
.substring(process.cwd().length + 1)
.split(sep)
.join('/');
const match = re.exec(p);
pkgs.push([key.replace('*', match?.[1]), dirname]);
}
}
} else {
const dirname = resolve(process.cwd(), dir);
pkgs.push([key, dirname]);
}
}
}
}
return pkgs;
}
function resolveNocobasePackagesAlias(config) {
const pkgs = getPackagePaths();
for (const [pkg, dir] of pkgs) {
config.module.rules.get('ts-in-node_modules').include.add(dir);
config.resolve.alias.set(pkg, dir);
}
}
class IndexGenerator {
constructor(outputPath, pluginsPath) {
this.outputPath = outputPath;
this.pluginsPath = pluginsPath;
}
get indexPath() {
return path.join(this.outputPath, 'index.ts');
}
get packageMapPath() {
return path.join(this.outputPath, 'packageMap.json');
}
get packagesPath() {
return path.join(this.outputPath, 'packages');
}
generate() {
this.generatePluginContent();
if (process.env.NODE_ENV === 'production') return;
this.pluginsPath.forEach((pluginPath) => {
if (!fs.existsSync(pluginPath)) {
return;
}
fs.watch(pluginPath, { recursive: false }, () => {
this.generatePluginContent();
});
});
}
get indexContent() {
return `// @ts-nocheck
import packageMap from './packageMap.json';
function devDynamicImport(packageName: string): Promise<any> {
const fileName = packageMap[packageName];
if (!fileName) {
return Promise.resolve(null);
}
return import(\`./packages/\${fileName}\`)
}
export default devDynamicImport;`;
}
get emptyIndexContent() {
return `
export default function devDynamicImport(packageName: string): Promise<any> {
return Promise.resolve(null);
}`;
}
generatePluginContent() {
if (fs.existsSync(this.outputPath)) {
fs.rmdirSync(this.outputPath, { recursive: true, force: true });
}
fs.mkdirSync(this.outputPath);
const validPluginPaths = this.pluginsPath.filter((pluginsPath) => fs.existsSync(pluginsPath));
if (!validPluginPaths.length || process.env.NODE_ENV === 'production') {
fs.writeFileSync(this.indexPath, this.emptyIndexContent);
return;
}
const pluginInfos = validPluginPaths.map((pluginsPath) => this.getContent(pluginsPath)).flat();
// index.ts
fs.writeFileSync(this.indexPath, this.indexContent);
// packageMap.json
const packageMapContent = pluginInfos.reduce((memo, item) => {
memo[item.packageJsonName] = item.pluginFileName + '.ts';
return memo;
}, {});
fs.writeFileSync(this.packageMapPath, JSON.stringify(packageMapContent, null, 2));
// packages
fs.mkdirSync(this.packagesPath, { recursive: true });
pluginInfos.forEach((item) => {
const pluginPackagePath = path.join(this.packagesPath, item.pluginFileName + '.ts');
fs.writeFileSync(pluginPackagePath, item.exportStatement);
});
}
getContent(pluginsPath) {
const pluginFolders = glob
.sync(['*/package.json', '*/*/package.json'], { cwd: pluginsPath, onlyFiles: true, absolute: true })
.map((item) => path.dirname(item));
const pluginInfos = pluginFolders
.filter((folder) => {
const pluginPackageJsonPath = path.join(folder, 'package.json');
const pluginSrcClientPath = path.join(folder, 'src', 'client');
return fs.existsSync(pluginPackageJsonPath) && fs.existsSync(pluginSrcClientPath);
})
.map((folder) => {
const pluginPackageJsonPath = path.join(folder, 'package.json');
const pluginPackageJson = require(pluginPackageJsonPath);
const pluginSrcClientPath = path
.relative(this.packagesPath, path.join(folder, 'src', 'client'))
.replaceAll('\\', '/');
const pluginFileName = `${path.basename(pluginsPath)}_${path.basename(folder).replaceAll('-', '_')}`;
const exportStatement = `export { default } from '${pluginSrcClientPath}';`;
return { exportStatement, pluginFileName, packageJsonName: pluginPackageJson.name };
});
return pluginInfos;
}
}
exports.getUmiConfig = getUmiConfig;
exports.resolveNocobasePackagesAlias = resolveNocobasePackagesAlias;
exports.IndexGenerator = IndexGenerator;