feat: add @nocobase/create-nocobase-app package

This commit is contained in:
chenos 2021-10-07 15:19:42 +08:00
parent 143ff2568c
commit 597c6484fb
27 changed files with 683 additions and 0 deletions

View File

@ -0,0 +1,5 @@
export default {
target: 'node',
cjs: { type: 'babel', lazy: true },
disableTypeCheck: true,
};

View File

@ -0,0 +1 @@
Used in bin/create-nocobase-app.js to determine if it is in the local debug state.

View File

@ -0,0 +1,7 @@
node_modules
*.log
docs
__tests__
tsconfig.json
src
.fatherrc.ts

View File

View File

@ -0,0 +1,3 @@
#!/usr/bin/env node
require('../lib/cli');

View File

@ -0,0 +1,23 @@
{
"name": "@nocobase/create-nocobase-app",
"version": "0.5.0-alpha.5",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"files": [
"lib",
"bin",
"templates"
],
"repository": {
"type": "git",
"url": "git+https://github.com/nocobase/nocobase.git",
"directory": "packages/create-nocobase-app"
},
"license": "MIT",
"dependencies": {
"@umijs/utils": "3.5.17"
},
"bin": {
"create-nocobase-app": "bin/create-nocobase-app.js"
}
}

View File

@ -0,0 +1,15 @@
import { Generator } from '@umijs/utils';
import { join } from 'path';
export default class AppGenerator extends Generator {
async writing() {
this.copyDirectory({
context: {
version: require('../../package').version,
conventionRoutes: this.args.conventionRoutes,
},
path: join(__dirname, '../../templates/AppGenerator'),
target: this.cwd,
});
}
}

View File

View File

@ -0,0 +1,30 @@
import { chalk, yParser } from '@umijs/utils';
import { existsSync } from 'fs';
import { join } from 'path';
const args = yParser(process.argv.slice(2), {
alias: {
version: ['v'],
help: ['h'],
},
boolean: ['version'],
});
if (args.version && !args._[0]) {
args._[0] = 'version';
const local = existsSync(join(__dirname, '../.local'))
? chalk.cyan('@local')
: '';
const { name, version } = require('../package.json');
console.log(`${name}@${version}${local}`);
} else {
require('./')
.default({
cwd: process.cwd(),
args,
})
.catch((err: Error) => {
console.error(`Create failed, ${err.message}`);
console.error(err);
});
}

View File

@ -0,0 +1,19 @@
import { rimraf } from '@umijs/utils';
import { existsSync } from 'fs';
import { join } from 'path';
import runGenerator from './index';
const fixtures = join(__dirname, 'fixtures');
const cwd = join(fixtures, 'generate');
test('generate app', async () => {
await runGenerator({
cwd,
args: {
_: [],
$0: '',
},
});
expect(existsSync(join(cwd, 'src', 'pages', 'index.tsx'))).toEqual(true);
rimraf.sync(cwd);
});

View File

@ -0,0 +1,16 @@
import { yargs } from '@umijs/utils';
import AppGenerator from './AppGenerator/AppGenerator';
export default async ({
cwd,
args,
}: {
cwd: string;
args: yargs.Arguments;
}) => {
const generator = new AppGenerator({
cwd,
args,
});
await generator.run();
};

View File

@ -0,0 +1,16 @@
# http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[Makefile]
indent_style = tab

View File

@ -0,0 +1,20 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/npm-debug.log*
/yarn-error.log
/yarn.lock
/package-lock.json
# production
/dist
# misc
.DS_Store
# umi
/src/.umi
/src/.umi-production
/src/.umi-test
/.env.local

View File

@ -0,0 +1,8 @@
**/*.md
**/*.svg
**/*.ejs
**/*.html
package.json
.umi
.umi-production
.umi-test

View File

@ -0,0 +1,11 @@
{
"singleQuote": true,
"trailingComma": "all",
"printWidth": 80,
"overrides": [
{
"files": ".prettierrc",
"options": { "parser": "json" }
}
]
}

View File

@ -0,0 +1,35 @@
import { defineConfig } from 'umi';
import dotenv from 'dotenv';
import path from 'path';
dotenv.config({
path: path.resolve(__dirname, '../../.env'),
});
export default defineConfig({
nodeModulesTransform: {
type: 'none',
},
define: {
'process.env.API_URL': process.env.API_URL,
'process.env.API_PORT': process.env.API_PORT,
},
proxy: {
'/api': {
'target': `http://localhost:${process.env.API_PORT}/`,
'changeOrigin': true,
'pathRewrite': { '^/api': '/api' },
},
},
routes: [
{ path: '/', exact: false, component: '@/pages/index' },
],
fastRefresh: {},
locale: {
default: 'zh-CN',
// antd: false,
// title: false,
baseNavigator: false,
baseSeparator: '-',
},
});

View File

@ -0,0 +1,15 @@
# NocoBase
## Getting Started
Install dependencies,
```bash
$ yarn
```
Start the dev server,
```bash
$ yarn start
```

View File

@ -0,0 +1,59 @@
{
"name": "root",
"private": true,
"scripts": {
"start": "concurrently \"npm run start-server\" \"umi dev\"",
"start-client": "umi dev",
"start-server": "ts-node-dev -r dotenv/config --project tsconfig.apis.json ./src/apis/index.ts",
"build": "npm run build-server && npm run build-client",
"build-client": "umi build",
"build-server": "rimraf -rf lib && tsc --project tsconfig.apis.json",
"postinstall": "umi generate tmp",
"prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'",
"test": "umi-test",
"test:coverage": "umi-test --coverage"
},
"gitHooks": {
"pre-commit": "lint-staged"
},
"lint-staged": {
"*.{js,jsx,less,md,json}": [
"prettier --write"
],
"*.ts?(x)": [
"prettier --parser=typescript --write"
]
},
"dependencies": {
"@nocobase/plugin-action-logs": "^0.5.0-alpha.2",
"@nocobase/plugin-china-region": "^0.5.0-alpha.2",
"@nocobase/plugin-client": "^0.5.0-alpha.2",
"@nocobase/plugin-collections": "^0.5.0-alpha.2",
"@nocobase/plugin-file-manager": "^0.5.0-alpha.2",
"@nocobase/plugin-multi-apps": "^0.5.0-alpha.2",
"@nocobase/plugin-permissions": "^0.5.0-alpha.2",
"@nocobase/plugin-ui-router": "^0.5.0-alpha.2",
"@nocobase/plugin-ui-schema": "^0.5.0-alpha.2",
"@nocobase/plugin-users": "^0.5.0-alpha.2",
"@nocobase/server": "^0.5.0-alpha.2"
},
"devDependencies": {
"@nocobase/client": "^0.5.0-alpha.2",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@umijs/preset-react": "1.x",
"@umijs/test": "^3.4.15",
"concurrently": "^5.3.0",
"core-js": "^3.18.2",
"cross-env": "^7.0.3",
"micromark": "^3.0.6",
"mockjs": "^1.1.0",
"prettier": "^2.2.0",
"react": "17.x",
"react-dom": "17.x",
"ts-node-dev": "^1.1.8",
"typescript": "4.1.5",
"umi": "^3.0.0",
"yorkie": "^2.0.0"
}
}

View File

@ -0,0 +1,71 @@
import Server from '@nocobase/server';
import path from 'path';
const start = Date.now();
const api = new Server({
database: {
username: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE,
host: process.env.DB_HOST,
port: process.env.DB_PORT as any,
dialect: process.env.DB_DIALECT as any,
dialectOptions: {
charset: 'utf8mb4',
collate: 'utf8mb4_unicode_ci',
},
pool: {
max: 5,
min: 0,
acquire: 60000,
idle: 10000,
},
logging: process.env.DB_LOG_SQL === 'on' ? console.log : false,
define: {},
sync: {
force: false,
alter: {
drop: false,
},
},
},
resourcer: {
prefix: '/api',
},
});
const plugins = [
'@nocobase/plugin-ui-router',
'@nocobase/plugin-ui-schema',
'@nocobase/plugin-collections',
'@nocobase/plugin-users',
'@nocobase/plugin-action-logs',
'@nocobase/plugin-file-manager',
'@nocobase/plugin-permissions',
'@nocobase/plugin-export',
'@nocobase/plugin-system-settings',
'@nocobase/plugin-china-region',
];
for (const plugin of plugins) {
api.plugin(
require(`${plugin}/lib/server`).default,
);
}
api.plugin(
require(`@nocobase/plugin-client/lib/server`).default, {
dist: path.resolve(process.cwd(), './dist'),
});
if (process.argv.length < 3) {
// @ts-ignore
process.argv.push('start', '--port', process.env.API_PORT);
}
console.log(process.argv);
api.parse(process.argv).then(() => {
console.log(`Start-up time: ${(Date.now() - start) / 1000}s`);
});

View File

@ -0,0 +1 @@
import './css_browser_selector';

View File

@ -0,0 +1,163 @@
/*
CSS Browser Selector 0.6.3
Originally written by Rafael Lima (http://rafael.adm.br)
http://rafael.adm.br/css_browser_selector
License: http://creativecommons.org/licenses/by/2.5/
Co-maintained by:
https://github.com/verbatim/css_browser_selector
*/
showLog=true;
function log(m) {if ( window.console && showLog ) {console.log(m); } }
function css_browser_selector(u) {
var uaInfo = {},
screens = [320, 480, 640, 768, 1024, 1152, 1280, 1440, 1680, 1920, 2560],
allScreens = screens.length,
ua=u.toLowerCase(),
is=function(t) { return RegExp(t,"i").test(ua); },
version = function(p,n)
{
n=n.replace(".","_"); var i = n.indexOf('_'), ver="";
while (i>0) {ver += " "+ p+n.substring(0,i);i = n.indexOf('_', i+1);}
ver += " "+p+n; return ver;
},
g='gecko',
w='webkit',
c='chrome',
f='firefox',
s='safari',
o='opera',
m='mobile',
a='android',
bb='blackberry',
lang='lang_',
dv='device_',
html=document.documentElement,
b= [
// browser
((!(/opera|webtv/i.test(ua))&&/msie\s(\d+)/.test(ua)||(/trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/.test(ua))))?('ie ie'+(/trident\/4\.0/.test(ua) ? '8' : RegExp.$1 == '11.0'?'11':RegExp.$1))
:is('firefox/')?g+ " " + f+(/firefox\/((\d+)(\.(\d+))(\.\d+)*)/.test(ua)?' '+f+RegExp.$2 + ' '+f+RegExp.$2+"_"+RegExp.$4:'')
:is('gecko/')?g
:is('opera')?o+(/version\/((\d+)(\.(\d+))(\.\d+)*)/.test(ua)?' '+o+RegExp.$2 + ' '+o+RegExp.$2+"_"+RegExp.$4 : (/opera(\s|\/)(\d+)\.(\d+)/.test(ua)?' '+o+RegExp.$2+" "+o+RegExp.$2+"_"+RegExp.$3:''))
:is('konqueror')?'konqueror'
:is('blackberry') ?
( bb +
( /Version\/(\d+)(\.(\d+)+)/i.test(ua)
? " " + bb+ RegExp.$1 + " "+bb+ RegExp.$1+RegExp.$2.replace('.','_')
: (/Blackberry ?(([0-9]+)([a-z]?))[\/|;]/gi.test(ua)
? ' ' +bb+RegExp.$2 + (RegExp.$3?' ' +bb+RegExp.$2+RegExp.$3:'')
: '')
)
) // blackberry
:is('android') ?
( a +
( /Version\/(\d+)(\.(\d+))+/i.test(ua)
? " " + a+ RegExp.$1 + " "+a+ RegExp.$1+RegExp.$2.replace('.','_')
: '')
+ (/Android (.+); (.+) Build/i.test(ua)
? ' '+dv+( (RegExp.$2).replace(/ /g,"_") ).replace(/-/g,"_")
:'' )
) //android
:is('chrome')?w+ ' '+c+(/chrome\/((\d+)(\.(\d+))(\.\d+)*)/.test(ua)?' '+c+RegExp.$2 +((RegExp.$4>0) ? ' '+c+RegExp.$2+"_"+RegExp.$4:''):'')
:is('iron')?w+' iron'
:is('applewebkit/') ?
( w+ ' '+ s +
( /version\/((\d+)(\.(\d+))(\.\d+)*)/.test(ua)
? ' '+ s +RegExp.$2 + " "+s+ RegExp.$2+RegExp.$3.replace('.','_')
: ( / Safari\/(\d+)/i.test(ua)
?
( (RegExp.$1=="419" || RegExp.$1=="417" || RegExp.$1=="416" || RegExp.$1=="412" ) ? ' '+ s + '2_0'
: RegExp.$1=="312" ? ' '+ s + '1_3'
: RegExp.$1=="125" ? ' '+ s + '1_2'
: RegExp.$1=="85" ? ' '+ s + '1_0'
: '' )
:'')
)
) //applewebkit
:is('mozilla/')?g
:''
// mobile
,is("android|mobi|mobile|j2me|iphone|ipod|ipad|blackberry|playbook|kindle|silk")?m:''
// os/platform
,is('j2me')?'j2me'
:is('ipad|ipod|iphone')?
(
(
/CPU( iPhone)? OS (\d+[_|\.]\d+([_|\.]\d+)*)/i.test(ua) ?
'ios' + version('ios',RegExp.$2) : ''
) + ' ' + ( /(ip(ad|od|hone))/gi.test(ua) ? RegExp.$1 : "" )
) //'iphone'
//:is('ipod')?'ipod'
//:is('ipad')?'ipad'
:is('playbook')?'playbook'
:is('kindle|silk')?'kindle'
:is('playbook')?'playbook'
:is('mac')?'mac'+ (/mac os x ((\d+)[.|_](\d+))/.test(ua) ? ( ' mac' + (RegExp.$2) + ' mac' + (RegExp.$1).replace('.',"_") ) : '' )
:is('win')?'win'+
(is('windows nt 6.2')?' win8'
:is('windows nt 6.1')?' win7'
:is('windows nt 6.0')?' vista'
:is('windows nt 5.2') || is('windows nt 5.1') ? ' win_xp'
:is('windows nt 5.0')?' win_2k'
:is('windows nt 4.0') || is('WinNT4.0') ?' win_nt'
: ''
)
:is('freebsd')?'freebsd'
:(is('x11|linux'))?'linux'
:''
// user agent language
,(/[; |\[](([a-z]{2})(\-[a-z]{2})?)[)|;|\]]/i.test(ua))?(lang+RegExp.$2).replace("-","_")+(RegExp.$3!=''?(' '+lang+RegExp.$1).replace("-","_"):''):''
// beta: test if running iPad app
,( is('ipad|iphone|ipod') && !is('safari') ) ? 'ipad_app' : ''
]; // b
console.debug(ua);
function screenSize() {
var w = window.outerWidth || html.clientWidth;
var h = window.outerHeight || html.clientHeight;
uaInfo.orientation = ((w<h) ? "portrait" : "landscape");
// remove previous min-width, max-width, client-width, client-height, and orientation
html.className = html.className.replace(/ ?orientation_\w+/g, "").replace(/ [min|max|cl]+[w|h]_\d+/g, "")
for (var i=(allScreens-1);i>=0;i--) { if (w >= screens[i] ) { uaInfo.maxw = screens[i]; break; }}
widthClasses="";
for (var info in uaInfo) { widthClasses+=" "+info+"_"+ uaInfo[info] };
html.className = ( html.className +widthClasses );
return widthClasses;
} // screenSize
window.onresize = screenSize;
screenSize();
function retina(){
var r = window.devicePixelRatio > 1;
if (r) {
html.className+=' retina';
}
else {
html.className+=' non-retina';
}
}
retina();
var cssbs = (b.join(' ')) + " js ";
html.className = ( cssbs + html.className.replace(/\b(no[-|_]?)?js\b/g,"") ).replace(/^ /, "").replace(/ +/g," ");
return cssbs;
}
css_browser_selector(navigator.userAgent);

View File

@ -0,0 +1,27 @@
.win {
/* width */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
/* Track */
::-webkit-scrollbar-track {
background: #f1f1f1;
}
/* Handle */
::-webkit-scrollbar-thumb {
background: #c0c0c0;
border-radius: 4px;
}
/* Handle on hover */
::-webkit-scrollbar-thumb:hover {
background: #a8a8a8;
}
.rc-virtual-list-scrollbar-thumb {
background: #c0c0c0 !important;
}
}

View File

@ -0,0 +1,3 @@
.title {
background: rgb(121, 242, 157);
}

View File

@ -0,0 +1,65 @@
import 'antd/dist/antd.css';
import { useRequest } from 'ahooks';
import { Spin } from 'antd';
import React, { useMemo } from 'react';
import { MemoryRouter as Router } from 'react-router-dom';
import {
createRouteSwitch,
AdminLayout,
AuthLayout,
RouteSchemaRenderer,
ConfigProvider,
ClientSDK,
} from '@nocobase/client';
import { extend } from 'umi-request';
console.log(`${location.protocol}//${location.hostname}:${process.env.API_PORT}/api/`);
const request = extend({
prefix: `${location.protocol}//${location.hostname}:${process.env.API_PORT}/api/`,
timeout: 30000,
});
request.use(async (ctx, next) => {
const { headers } = ctx.req.options as any;
const token = localStorage.getItem('NOCOBASE_TOKEN');
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
headers['X-Hostname'] = window.location.hostname;
await next();
});
const client = new ClientSDK({ request });
const RouteSwitch = createRouteSwitch({
components: {
AdminLayout,
AuthLayout,
RouteSchemaRenderer,
},
});
const App = () => {
const { data, loading } = useRequest('routes:getAccessible', {
formatResult: (result) => result?.data,
});
if (loading) {
return <Spin />;
}
return (
<div>
<RouteSwitch routes={data} />
</div>
);
};
export default function IndexPage() {
return (
<ConfigProvider client={client}>
<App />
</ConfigProvider>
);
}

View File

@ -0,0 +1,24 @@
{
"compilerOptions": {
"esModuleInterop": true,
"moduleResolution": "node",
"jsx": "react",
"module": "commonjs",
"target": "ES6",
"allowJs": false,
"noUnusedLocals": false,
"removeComments": true,
"preserveConstEnums": true,
"sourceMap": true,
"declaration": true,
"experimentalDecorators": true,
"downlevelIteration": true,
"baseUrl": ".",
"outDir": "./lib/apis",
"paths": {
}
},
"include": [
"src/apis",
]
}

View File

@ -0,0 +1,36 @@
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"importHelpers": true,
"jsx": "react-jsx",
"esModuleInterop": true,
"sourceMap": true,
"baseUrl": "./",
"strict": true,
"paths": {
"@/*": ["src/*"],
"@@/*": ["src/.umi/*"]
},
"allowSyntheticDefaultImports": true
},
"include": [
"mock/**/*",
"src/**/*",
"config/**/*",
".umirc.ts",
"typings.d.ts"
],
"exclude": [
"node_modules",
"lib",
"es",
"dist",
"typings",
"**/__test__",
"test",
"docs",
"tests"
]
}

View File

@ -0,0 +1,10 @@
declare module '*.css';
declare module '*.less';
declare module '*.png';
declare module '*.svg' {
export function ReactComponent(
props: React.SVGProps<SVGSVGElement>,
): React.ReactElement;
const url: string;
export default url;
}