oak-cli 项目新建
This commit is contained in:
parent
8511d289be
commit
430dace767
|
|
@ -83,4 +83,6 @@ dist
|
||||||
.yarn/unplugged
|
.yarn/unplugged
|
||||||
.yarn/build-state.yml
|
.yarn/build-state.yml
|
||||||
.yarn/install-state.gz
|
.yarn/install-state.gz
|
||||||
.pnp.*
|
.pnp.*
|
||||||
|
|
||||||
|
package-lock.json
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
/** 环境变量 */
|
||||||
|
exports.NODE_ENV = process.argv.splice(2, 1)[0];
|
||||||
|
/** 项目路径 */
|
||||||
|
exports.ROOT = path.join(process.cwd(), 'wechatMp');
|
||||||
|
/** 源代码存放路径 */
|
||||||
|
exports.SOURCE = path.resolve(this.ROOT, 'src');
|
||||||
|
/** 目标代码存放路径 */
|
||||||
|
exports.DESTINATION = path.resolve(this.ROOT, 'dist');
|
||||||
|
/** 配置脚本文件路径 */
|
||||||
|
exports.SCRIPTS = path.resolve(this.ROOT, 'scripts');
|
||||||
|
/** .env 配置文件路径 */
|
||||||
|
exports.ENV_CONFIG = path.resolve(this.ROOT, '.env');
|
||||||
|
/** 默认配置文件 */
|
||||||
|
exports.DEFAULT_CONFIG = {
|
||||||
|
platform: 'wx',
|
||||||
|
css_unit_ratio: 1,
|
||||||
|
};
|
||||||
|
/** 平台映射字典 */
|
||||||
|
exports.PLATFORM_CONFIG = {
|
||||||
|
wx: {
|
||||||
|
template: '.wxml',
|
||||||
|
style: '.wxss',
|
||||||
|
},
|
||||||
|
swan: {
|
||||||
|
template: '.swan',
|
||||||
|
style: '.css',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,171 @@
|
||||||
|
const webpack = require('webpack');
|
||||||
|
const chalk = require('chalk');
|
||||||
|
const path = require('path');
|
||||||
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||||
|
const StylelintPlugin = require('stylelint-webpack-plugin');
|
||||||
|
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
|
||||||
|
const UiExtractPlugin = require('ui-extract-webpack-plugin');
|
||||||
|
const Dotenv = require('dotenv-webpack');
|
||||||
|
// const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
||||||
|
const OakWeChatMpPlugin = require('../plugins/WechatMpPlugin');
|
||||||
|
|
||||||
|
const {
|
||||||
|
ROOT,
|
||||||
|
SOURCE,
|
||||||
|
DESTINATION,
|
||||||
|
NODE_ENV,
|
||||||
|
PLATFORM_CONFIG,
|
||||||
|
ENV_CONFIG,
|
||||||
|
} = require('./env');
|
||||||
|
const __DEV__ = NODE_ENV === 'development';
|
||||||
|
|
||||||
|
const relativeFileLoader = (ext = '[ext]') => {
|
||||||
|
return {
|
||||||
|
loader: 'file-loader',
|
||||||
|
options: {
|
||||||
|
useRelativePath: true,
|
||||||
|
name: `[path][name].${ext}`,
|
||||||
|
context: SOURCE,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const oakLoader = (ext = '[ext]') => {
|
||||||
|
return {
|
||||||
|
loader: 'file-loader',
|
||||||
|
options: {
|
||||||
|
useRelativePath: true,
|
||||||
|
name: `[path][name].${ext}`,
|
||||||
|
outputPath: (url, resourcePath, context) => {
|
||||||
|
const outputPath = url.split(
|
||||||
|
'oak-general-business/src/platforms/wechatMp/'
|
||||||
|
)[1];
|
||||||
|
return outputPath;
|
||||||
|
},
|
||||||
|
context: SOURCE,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
context: SOURCE,
|
||||||
|
devtool: __DEV__ ? 'source-map' : false,
|
||||||
|
mode: NODE_ENV,
|
||||||
|
target: 'web',
|
||||||
|
entry: {
|
||||||
|
app: '../src/app',
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
filename: '[name].js',
|
||||||
|
path: DESTINATION,
|
||||||
|
publicPath: '/',
|
||||||
|
globalObject: 'global',
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@': SOURCE,
|
||||||
|
assert: require.resolve('assert'),
|
||||||
|
},
|
||||||
|
extensions: ['.ts', '.js', 'json'],
|
||||||
|
symlinks: true,
|
||||||
|
fallback: {
|
||||||
|
crypto: require.resolve('crypto-browserify'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.less$/,
|
||||||
|
include: /src/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
use: [
|
||||||
|
relativeFileLoader('wxss'),
|
||||||
|
{
|
||||||
|
loader: 'less-loader',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.less$/,
|
||||||
|
include: /oak-general-business/,
|
||||||
|
type: 'javascript/auto',
|
||||||
|
use: [
|
||||||
|
oakLoader('wxss'),
|
||||||
|
{
|
||||||
|
loader: 'less-loader',
|
||||||
|
options: {
|
||||||
|
lessOptions: () => {
|
||||||
|
const oakConfigJson = require(`${SOURCE}/oak.config.json`);
|
||||||
|
return {
|
||||||
|
javascriptEnabled: true,
|
||||||
|
modifyVars: oakConfigJson.theme,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.js$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
loader: 'babel-loader',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.ts$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
loader: 'ts-loader',
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// test: /\.json$/,
|
||||||
|
// include: /src/,
|
||||||
|
// type: 'asset/resource',
|
||||||
|
// generator: {
|
||||||
|
// filename: `[path][name].[ext]`,
|
||||||
|
// },
|
||||||
|
// // type: 'javascript/auto',
|
||||||
|
// // use: [relativeFileLoader('json')],
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
test: /\.(xml|wxml)$/,
|
||||||
|
include: /src/,
|
||||||
|
type: 'asset/resource',
|
||||||
|
generator: {
|
||||||
|
filename: `[path][name].[ext]`,
|
||||||
|
},
|
||||||
|
// use: [relativeFileLoader('wxml')],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
// new CleanWebpackPlugin(),
|
||||||
|
new UiExtractPlugin({ context: SOURCE }),
|
||||||
|
new OakWeChatMpPlugin({
|
||||||
|
exclude: ['*/weui-miniprogram/*'],
|
||||||
|
include: ['project.config.json', 'sitemap.json'],
|
||||||
|
}),
|
||||||
|
/* new webpack.DefinePlugin({
|
||||||
|
['process.env.NODE_ENV']: JSON.stringify(NODE_ENV),
|
||||||
|
}), */
|
||||||
|
// new MiniCssExtractPlugin({ filename: `[name]${PLATFORM_CONFIG[yamlConfig.platform].style}` }),
|
||||||
|
new StylelintPlugin({
|
||||||
|
fix: true,
|
||||||
|
files: '**/*.(sa|sc|le|wx|c)ss',
|
||||||
|
}),
|
||||||
|
new ProgressBarPlugin({
|
||||||
|
summary: false,
|
||||||
|
format: ':msg :percent (:elapsed seconds)',
|
||||||
|
customSummary: (buildTime) =>
|
||||||
|
console.log(
|
||||||
|
chalk.gray(`\n[${new Date().toLocaleDateString()}`),
|
||||||
|
chalk.green(`Compiled successfully!(${buildTime})\n`)
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
new Dotenv({ path: ENV_CONFIG, silent: true }),
|
||||||
|
],
|
||||||
|
watch: true,
|
||||||
|
watchOptions: {
|
||||||
|
aggregateTimeout: 600,
|
||||||
|
ignored: '**/node_modules',
|
||||||
|
followSymlinks: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
export default function build(env: string): Promise<void>;
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const tip_style_1 = require("./tip-style");
|
||||||
|
const cross_spawn_1 = __importDefault(require("cross-spawn"));
|
||||||
|
async function build(env) {
|
||||||
|
(0, tip_style_1.Success)(`${(0, tip_style_1.success)(`build环境:${env}`)}`);
|
||||||
|
const result = cross_spawn_1.default.sync(process.execPath, [require.resolve('../scripts/' + 'webpack.js')].concat([env]), {
|
||||||
|
stdio: 'inherit',
|
||||||
|
shell: true,
|
||||||
|
});
|
||||||
|
// const result = spawn.sync('npm -v', [], { stdio: 'inherit', shell: true });
|
||||||
|
if (result.status === 0) {
|
||||||
|
(0, tip_style_1.Success)(`${(0, tip_style_1.success)(`执行完成`)}`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
(0, tip_style_1.Error)(`${(0, tip_style_1.error)(`执行失败`)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.default = build;
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
export declare const CLI_VERSION: any;
|
||||||
|
export declare const CLI_NAME: any;
|
||||||
|
export declare const BASE_DIR: string;
|
||||||
|
export declare const USER_CONFIG_FILE_NAME = "oak.config.json";
|
||||||
|
export declare const USER_CONFIG_FILE: string;
|
||||||
|
export declare const NODE_MODULES_DIR_NAME = "node_modules";
|
||||||
|
export declare const CNPM_BASE_URL = "";
|
||||||
|
export declare const MINI_VERSION_URL = "https://mp.weixin.qq.com/debug/getpublibpercentage";
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.MINI_VERSION_URL = exports.CNPM_BASE_URL = exports.NODE_MODULES_DIR_NAME = exports.USER_CONFIG_FILE = exports.USER_CONFIG_FILE_NAME = exports.BASE_DIR = exports.CLI_NAME = exports.CLI_VERSION = void 0;
|
||||||
|
exports.CLI_VERSION = require('../package.json')['version'];
|
||||||
|
exports.CLI_NAME = require('../package.json')['name'];
|
||||||
|
exports.BASE_DIR = process.cwd();
|
||||||
|
exports.USER_CONFIG_FILE_NAME = 'oak.config.json';
|
||||||
|
exports.USER_CONFIG_FILE = exports.BASE_DIR + '/' + exports.USER_CONFIG_FILE_NAME;
|
||||||
|
exports.NODE_MODULES_DIR_NAME = 'node_modules';
|
||||||
|
exports.CNPM_BASE_URL = ''; //oak-cli
|
||||||
|
exports.MINI_VERSION_URL = 'https://mp.weixin.qq.com/debug/getpublibpercentage';
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
export default function create(dirName: string, env: string): Promise<void>;
|
||||||
|
|
@ -0,0 +1,145 @@
|
||||||
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const file_handle_1 = require("./file-handle");
|
||||||
|
const enum_1 = require("./enum");
|
||||||
|
const config_1 = require("./config");
|
||||||
|
const template_1 = require("./template");
|
||||||
|
const path_1 = require("path");
|
||||||
|
const inquirer_1 = __importDefault(require("inquirer"));
|
||||||
|
const axios_1 = __importDefault(require("axios"));
|
||||||
|
const tip_style_1 = require("./tip-style");
|
||||||
|
const shelljs_1 = __importDefault(require("shelljs"));
|
||||||
|
const prompt = [
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
name: 'version',
|
||||||
|
message: 'version',
|
||||||
|
default: '1.0.0',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
name: 'description',
|
||||||
|
message: 'description',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
/**
|
||||||
|
* @name 检查项目名是否已存在
|
||||||
|
* @param dirName
|
||||||
|
*/
|
||||||
|
function checkProjectName(dirName) {
|
||||||
|
// 项目根路径
|
||||||
|
const rootPath = process.cwd() + '/' + dirName;
|
||||||
|
const isExists = (0, file_handle_1.checkFileExists)(rootPath);
|
||||||
|
if (isExists) {
|
||||||
|
console.error((0, tip_style_1.error)(`Cannot create a project named ${(0, tip_style_1.success)(`"${dirName}"`)} because a path with the same name exists.\n`) + (0, tip_style_1.error)('Please choose a different project name.'));
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @name 获取oak-cli最新版本号
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async function getOakCliVersion() {
|
||||||
|
const res = await axios_1.default.get(config_1.CNPM_BASE_URL);
|
||||||
|
return res.data['dist-tags']['latest'];
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @name 获取微信小程序稳定基础版本库
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async function getMiniVersion() {
|
||||||
|
const res = await axios_1.default.get(config_1.MINI_VERSION_URL);
|
||||||
|
const versions = JSON.parse(res.data['json_data'])['total'];
|
||||||
|
const versionsSort = versions.sort((a, b) => {
|
||||||
|
return b['percentage'] - a['percentage'];
|
||||||
|
});
|
||||||
|
return versionsSort[0]['sdkVer'];
|
||||||
|
}
|
||||||
|
async function create(dirName, env) {
|
||||||
|
const nameOption = {
|
||||||
|
type: 'input',
|
||||||
|
name: 'name',
|
||||||
|
message: `name`,
|
||||||
|
default: dirName,
|
||||||
|
};
|
||||||
|
prompt.unshift(nameOption);
|
||||||
|
const isDev = env === 'dev' || env === 'development';
|
||||||
|
const { name, version, description } = await inquirer_1.default.prompt(prompt);
|
||||||
|
// 获取微信小程序稳定基础版本库
|
||||||
|
const miniVersion = await getMiniVersion();
|
||||||
|
// 获取package.json内容
|
||||||
|
const packageJson = (0, template_1.packageJsonContent)({
|
||||||
|
name,
|
||||||
|
version,
|
||||||
|
description,
|
||||||
|
cliversion: config_1.CLI_VERSION,
|
||||||
|
cliname: config_1.CLI_NAME,
|
||||||
|
isDev,
|
||||||
|
});
|
||||||
|
// 获取tsconfig.json内容
|
||||||
|
const tsconfigJson = (0, template_1.tsConfigJsonContent)();
|
||||||
|
// 获取小程序项目project.config.json内容
|
||||||
|
const projectConfigWithWeChatMp = (0, template_1.projectConfigContentWithWeChatMp)(config_1.USER_CONFIG_FILE_NAME, 'wechatMp', miniVersion);
|
||||||
|
// 获取小程序项目oak.config.json内容
|
||||||
|
const oakConfigWithWeChatMp = (0, template_1.oakConfigContentWithWeChatMp)();
|
||||||
|
// 项目根路径
|
||||||
|
const rootPath = process.cwd() + '/' + dirName;
|
||||||
|
// package.json路径
|
||||||
|
const packageJsonPath = `${rootPath}/package.json`;
|
||||||
|
// tsconfig.json路径
|
||||||
|
const tsconfigJsonPath = `${rootPath}/tsconfig.json`;
|
||||||
|
// web项目根路径
|
||||||
|
const webRootPath = `${rootPath}/web`;
|
||||||
|
// 小程序项目根路径
|
||||||
|
const weChatMpRootPath = `${rootPath}/wechatMp`;
|
||||||
|
// 小程序项目project.config.json路径
|
||||||
|
const projectConfigPathWithWeChatMp = `${weChatMpRootPath}/src/project.config.json`;
|
||||||
|
// 小程序项目project.config.json路径
|
||||||
|
const oakConfigPathWithWeChatMp = `${weChatMpRootPath}/src/${config_1.USER_CONFIG_FILE_NAME}`;
|
||||||
|
// 被复制的文件夹路径
|
||||||
|
const currentPath = (0, path_1.join)(__dirname, '..') + '/template';
|
||||||
|
//检查项目名是否存在
|
||||||
|
checkProjectName(dirName);
|
||||||
|
try {
|
||||||
|
// 创建根目录
|
||||||
|
(0, file_handle_1.checkFileExistsAndCreate)(rootPath);
|
||||||
|
// 创建package.json
|
||||||
|
(0, file_handle_1.checkFileExistsAndCreate)(packageJsonPath, packageJson, enum_1.checkFileExistsAndCreateType.FILE);
|
||||||
|
// 创建tsconfig.json
|
||||||
|
(0, file_handle_1.checkFileExistsAndCreate)(tsconfigJsonPath, tsconfigJson, enum_1.checkFileExistsAndCreateType.FILE);
|
||||||
|
// 复制项目文件
|
||||||
|
(0, file_handle_1.copyFolder)(currentPath, rootPath);
|
||||||
|
// 创建小程序项目project.config.json
|
||||||
|
(0, file_handle_1.checkFileExistsAndCreate)(projectConfigPathWithWeChatMp, projectConfigWithWeChatMp, enum_1.checkFileExistsAndCreateType.FILE);
|
||||||
|
// 创建小程序项目oak.config.json
|
||||||
|
(0, file_handle_1.checkFileExistsAndCreate)(oakConfigPathWithWeChatMp, oakConfigWithWeChatMp, enum_1.checkFileExistsAndCreateType.FILE);
|
||||||
|
if (!shelljs_1.default.which('npm')) {
|
||||||
|
(0, tip_style_1.Warn)((0, tip_style_1.warn)('Sorry, this script requires npm! Please install npm!'));
|
||||||
|
shelljs_1.default.exit(1);
|
||||||
|
}
|
||||||
|
(0, tip_style_1.Success)(`${(0, tip_style_1.success)(`Waiting...`)}`);
|
||||||
|
(0, tip_style_1.Success)(`${(0, tip_style_1.success)(`Dependencies are now being installed`)}`);
|
||||||
|
shelljs_1.default.cd(dirName).exec('npm install');
|
||||||
|
// checkFileExistsAndCreate(weChatMpRootPath + '/src/styles');
|
||||||
|
// //const data = readFile(
|
||||||
|
// // `${rootPath}/node_modules/oak-frontend-boilerplate/src/platforms/wechatMp/styles/base.less`
|
||||||
|
// //);
|
||||||
|
// const data = readFile(
|
||||||
|
// `${rootPath}/node_modules/oak-general-business/src/platforms/wechatMp/styles/base.less`
|
||||||
|
// );
|
||||||
|
// checkFileExistsAndCreate(
|
||||||
|
// weChatMpRootPath + '/src/styles/base.less',
|
||||||
|
// data,
|
||||||
|
// checkFileExistsAndCreateType.FILE
|
||||||
|
// );
|
||||||
|
(0, tip_style_1.Success)(`${(0, tip_style_1.success)(`Successfully created project ${(0, tip_style_1.primary)(name)}, directory name is ${(0, tip_style_1.primary)(dirName)}`)}`);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
(0, tip_style_1.Error)((0, tip_style_1.error)('create error'));
|
||||||
|
(0, tip_style_1.Error)((0, tip_style_1.error)(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.default = create;
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
/**
|
||||||
|
* @name 检查文件时用到的枚举
|
||||||
|
* @export
|
||||||
|
* @enum {number}
|
||||||
|
*/
|
||||||
|
export declare enum checkFileExistsAndCreateType {
|
||||||
|
DIRECTORY = 0,
|
||||||
|
FILE = 1
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.checkFileExistsAndCreateType = void 0;
|
||||||
|
/**
|
||||||
|
* @name 检查文件时用到的枚举
|
||||||
|
* @export
|
||||||
|
* @enum {number}
|
||||||
|
*/
|
||||||
|
var checkFileExistsAndCreateType;
|
||||||
|
(function (checkFileExistsAndCreateType) {
|
||||||
|
checkFileExistsAndCreateType[checkFileExistsAndCreateType["DIRECTORY"] = 0] = "DIRECTORY";
|
||||||
|
checkFileExistsAndCreateType[checkFileExistsAndCreateType["FILE"] = 1] = "FILE";
|
||||||
|
})(checkFileExistsAndCreateType = exports.checkFileExistsAndCreateType || (exports.checkFileExistsAndCreateType = {}));
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
/// <reference types="node" />
|
||||||
|
import { PathLike } from 'fs';
|
||||||
|
import { checkFileExistsAndCreateType } from './enum';
|
||||||
|
/**
|
||||||
|
* @name 读取目录下所有文件
|
||||||
|
* @export
|
||||||
|
* @param {string} entry 目录名称
|
||||||
|
*/
|
||||||
|
export declare function readDirPath(entry: string): Set<string>;
|
||||||
|
/**
|
||||||
|
* @name 读取指定目录的文件(不进行深度遍历,只获取根目录)
|
||||||
|
* @export
|
||||||
|
* @param {*} entry
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export declare function readDirGetFile(entry: string): string[];
|
||||||
|
/**
|
||||||
|
* @name 解析json文件(数组)
|
||||||
|
* @export
|
||||||
|
* @param {Array<string>} arr
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export declare function parseJsonFiles(arr: Set<string>): any[];
|
||||||
|
/**
|
||||||
|
* @name 解析单个文件json
|
||||||
|
* @export
|
||||||
|
* @param {PathLike} file
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export declare function parseJsonFile(file: string): any;
|
||||||
|
/**
|
||||||
|
* @name 删除文件夹
|
||||||
|
* @export
|
||||||
|
* @param {string} entry
|
||||||
|
*/
|
||||||
|
export declare function deleteFolderRecursive(entry: string): void;
|
||||||
|
export declare function writeFile(path: string | PathLike, data: any): void;
|
||||||
|
export declare function readFile(path: string | PathLike, options?: {
|
||||||
|
encoding?: null | undefined;
|
||||||
|
flag?: string | undefined;
|
||||||
|
} | null): Buffer | undefined;
|
||||||
|
/**
|
||||||
|
* @name 拷贝文件夹
|
||||||
|
* @export
|
||||||
|
* @param {PathLike} currentDir
|
||||||
|
* @param {PathLike} targetDir
|
||||||
|
*/
|
||||||
|
export declare function copyFolder(currentDir: PathLike, targetDir: PathLike): void;
|
||||||
|
/**
|
||||||
|
* @name 检测文件/文件夹是否存在
|
||||||
|
* @export
|
||||||
|
* @param {(PathLike | string)} path
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export declare function checkFileExists(path: PathLike | string): boolean;
|
||||||
|
/**
|
||||||
|
* @name 检测文件/文件夹是否存在,不存在则创建
|
||||||
|
* @export
|
||||||
|
* @param {(PathLike | string)} path
|
||||||
|
* @param {*} [data]
|
||||||
|
* @param {checkFileExistsAndCreateType} [type=checkFileExistsAndCreateType.DIRECTORY]
|
||||||
|
*/
|
||||||
|
export declare function checkFileExistsAndCreate(path: PathLike | string, data?: any, type?: checkFileExistsAndCreateType): void;
|
||||||
|
|
@ -0,0 +1,206 @@
|
||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.checkFileExistsAndCreate = exports.checkFileExists = exports.copyFolder = exports.readFile = exports.writeFile = exports.deleteFolderRecursive = exports.parseJsonFile = exports.parseJsonFiles = exports.readDirGetFile = exports.readDirPath = void 0;
|
||||||
|
const fs_1 = require("fs");
|
||||||
|
const path_1 = require("path");
|
||||||
|
const enum_1 = require("./enum");
|
||||||
|
const tip_style_1 = require("./tip-style");
|
||||||
|
const pathList = new Set();
|
||||||
|
/**
|
||||||
|
* @name 读取目录下所有文件
|
||||||
|
* @export
|
||||||
|
* @param {string} entry 目录名称
|
||||||
|
*/
|
||||||
|
function readDirPath(entry) {
|
||||||
|
const dirInfo = (0, fs_1.readdirSync)(entry);
|
||||||
|
for (let item of dirInfo) {
|
||||||
|
const location = (0, path_1.join)(entry, item);
|
||||||
|
const info = (0, fs_1.statSync)(location);
|
||||||
|
if (info.isDirectory()) {
|
||||||
|
readDirPath(location);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pathList.add(location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pathList;
|
||||||
|
}
|
||||||
|
exports.readDirPath = readDirPath;
|
||||||
|
/**
|
||||||
|
* @name 读取指定目录的文件(不进行深度遍历,只获取根目录)
|
||||||
|
* @export
|
||||||
|
* @param {*} entry
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function readDirGetFile(entry) {
|
||||||
|
const dirInfo = (0, fs_1.readdirSync)(entry);
|
||||||
|
return dirInfo;
|
||||||
|
}
|
||||||
|
exports.readDirGetFile = readDirGetFile;
|
||||||
|
/**
|
||||||
|
* @name 解析json文件(数组)
|
||||||
|
* @export
|
||||||
|
* @param {Array<string>} arr
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function parseJsonFiles(arr) {
|
||||||
|
const result = [];
|
||||||
|
for (let item of arr) {
|
||||||
|
const data = parseJsonFile(item);
|
||||||
|
result.push(data);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
exports.parseJsonFiles = parseJsonFiles;
|
||||||
|
/**
|
||||||
|
* @name 解析单个文件json
|
||||||
|
* @export
|
||||||
|
* @param {PathLike} file
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function parseJsonFile(file) {
|
||||||
|
try {
|
||||||
|
const data = (0, fs_1.readFileSync)(file, 'utf8');
|
||||||
|
return JSON.parse(data);
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.parseJsonFile = parseJsonFile;
|
||||||
|
/**
|
||||||
|
* @name 删除文件夹
|
||||||
|
* @export
|
||||||
|
* @param {string} entry
|
||||||
|
*/
|
||||||
|
function deleteFolderRecursive(entry) {
|
||||||
|
let files = [];
|
||||||
|
// 判断给定的路径是否存在
|
||||||
|
if ((0, fs_1.existsSync)(entry)) {
|
||||||
|
// 返回文件和子目录的数组
|
||||||
|
files = (0, fs_1.readdirSync)(entry);
|
||||||
|
for (let file of files) {
|
||||||
|
const curPath = (0, path_1.join)(entry, file);
|
||||||
|
// fs.statSync同步读取文件夹文件,如果是文件夹,在重复触发函数
|
||||||
|
if ((0, fs_1.statSync)(curPath).isDirectory()) { // recurse
|
||||||
|
deleteFolderRecursive(curPath);
|
||||||
|
// 是文件delete file
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
(0, fs_1.unlinkSync)(curPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 清除文件夹
|
||||||
|
(0, fs_1.rmdirSync)(entry);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// console.log("文件夹不存在");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.deleteFolderRecursive = deleteFolderRecursive;
|
||||||
|
;
|
||||||
|
function writeFile(path, data) {
|
||||||
|
try {
|
||||||
|
(0, fs_1.writeFileSync)(path, data);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
(0, tip_style_1.Error)((0, tip_style_1.error)(err));
|
||||||
|
(0, tip_style_1.Error)((0, tip_style_1.error)('文件写入失败'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.writeFile = writeFile;
|
||||||
|
function readFile(path, options) {
|
||||||
|
try {
|
||||||
|
const data = (0, fs_1.readFileSync)(path, options);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
(0, tip_style_1.Error)((0, tip_style_1.error)(err));
|
||||||
|
(0, tip_style_1.Error)((0, tip_style_1.error)('文件读取失败'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.readFile = readFile;
|
||||||
|
/**
|
||||||
|
* @name 拷贝文件夹
|
||||||
|
* @export
|
||||||
|
* @param {PathLike} currentDir
|
||||||
|
* @param {PathLike} targetDir
|
||||||
|
*/
|
||||||
|
function copyFolder(currentDir, targetDir) {
|
||||||
|
function handleFolder(currentDir, targetDir) {
|
||||||
|
const files = (0, fs_1.readdirSync)(currentDir, {
|
||||||
|
withFileTypes: true
|
||||||
|
});
|
||||||
|
for (let file of files) {
|
||||||
|
// 拼接文件绝对路径
|
||||||
|
const copyCurrentFileInfo = currentDir + '/' + file.name;
|
||||||
|
const copyTargetFileInfo = targetDir + '/' + file.name;
|
||||||
|
// 判断文件是否存在
|
||||||
|
const readCurrentFile = (0, fs_1.existsSync)(copyCurrentFileInfo);
|
||||||
|
const readTargetFile = (0, fs_1.existsSync)(copyTargetFileInfo);
|
||||||
|
if (readCurrentFile && !readTargetFile) {
|
||||||
|
// 判断是否为文件,如果为文件则复制,文件夹则递归
|
||||||
|
if (file.isFile()) {
|
||||||
|
const readStream = (0, fs_1.createReadStream)(copyCurrentFileInfo);
|
||||||
|
const writeStream = (0, fs_1.createWriteStream)(copyTargetFileInfo);
|
||||||
|
readStream.pipe(writeStream);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
try {
|
||||||
|
(0, fs_1.accessSync)((0, path_1.join)(copyTargetFileInfo, '..'), fs_1.constants.W_OK);
|
||||||
|
copyFolder(copyCurrentFileInfo, copyTargetFileInfo);
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
(0, tip_style_1.Warn)('权限不足' + error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
(0, tip_style_1.Error)((0, tip_style_1.error)('操作失败,target文件夹已存在或current文件夹不存在'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((0, fs_1.existsSync)(currentDir)) {
|
||||||
|
if (!(0, fs_1.existsSync)(targetDir)) {
|
||||||
|
(0, fs_1.mkdirSync)(targetDir);
|
||||||
|
}
|
||||||
|
handleFolder(currentDir, targetDir);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
(0, tip_style_1.Warn)((0, tip_style_1.warn)('需要copy的文件夹不存在:' + currentDir));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.copyFolder = copyFolder;
|
||||||
|
/**
|
||||||
|
* @name 检测文件/文件夹是否存在
|
||||||
|
* @export
|
||||||
|
* @param {(PathLike | string)} path
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function checkFileExists(path) {
|
||||||
|
return (0, fs_1.existsSync)(path);
|
||||||
|
}
|
||||||
|
exports.checkFileExists = checkFileExists;
|
||||||
|
/**
|
||||||
|
* @name 检测文件/文件夹是否存在,不存在则创建
|
||||||
|
* @export
|
||||||
|
* @param {(PathLike | string)} path
|
||||||
|
* @param {*} [data]
|
||||||
|
* @param {checkFileExistsAndCreateType} [type=checkFileExistsAndCreateType.DIRECTORY]
|
||||||
|
*/
|
||||||
|
function checkFileExistsAndCreate(path, data, type = enum_1.checkFileExistsAndCreateType.DIRECTORY) {
|
||||||
|
if (!checkFileExists(path)) {
|
||||||
|
switch (type) {
|
||||||
|
case enum_1.checkFileExistsAndCreateType.DIRECTORY:
|
||||||
|
(0, fs_1.mkdirSync)(path);
|
||||||
|
break;
|
||||||
|
case enum_1.checkFileExistsAndCreateType.FILE:
|
||||||
|
writeFile(path, data);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
(0, fs_1.mkdirSync)(path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.checkFileExistsAndCreate = checkFileExistsAndCreate;
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
export {};
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const commander_1 = __importDefault(require("commander"));
|
||||||
|
const create_1 = __importDefault(require("./create"));
|
||||||
|
const build_1 = __importDefault(require("./build"));
|
||||||
|
const make_1 = __importDefault(require("./make"));
|
||||||
|
const config_1 = require("./config");
|
||||||
|
const tip_style_1 = require("./tip-style");
|
||||||
|
/**
|
||||||
|
* @name 未知参数错误提示
|
||||||
|
* @param {string} methodName
|
||||||
|
* @param {Function} log
|
||||||
|
*/
|
||||||
|
function enhanceErrorMessages(methodName, log) {
|
||||||
|
commander_1.default.Command.prototype[methodName] = function (...args) {
|
||||||
|
if (methodName === 'unknownOption' && this._allowUnknownOption) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.outputHelp();
|
||||||
|
console.log(` ` + (0, tip_style_1.error)(log(...args)));
|
||||||
|
console.log();
|
||||||
|
process.exit(1);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const currentNodeVersion = process.versions.node;
|
||||||
|
const semver = currentNodeVersion.split('.');
|
||||||
|
const major = semver[0];
|
||||||
|
const minNodeVersion = 14;
|
||||||
|
if (Number(major) < minNodeVersion) {
|
||||||
|
console.error('You are running Node ' +
|
||||||
|
currentNodeVersion +
|
||||||
|
'.\n' +
|
||||||
|
'Create React App requires Node ' +
|
||||||
|
minNodeVersion +
|
||||||
|
' or higher. \n' +
|
||||||
|
'Please update your version of Node.');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
commander_1.default.version(config_1.CLI_VERSION, '-v, --version').usage('<command> [options]');
|
||||||
|
commander_1.default
|
||||||
|
.command('make')
|
||||||
|
.description('build oak app domain of make on demand')
|
||||||
|
.action(make_1.default);
|
||||||
|
commander_1.default
|
||||||
|
.command('start <env>')
|
||||||
|
.usage('<env>')
|
||||||
|
.description('build we chat mp of start on demand')
|
||||||
|
.action(build_1.default);
|
||||||
|
commander_1.default
|
||||||
|
.command('build <env>')
|
||||||
|
.usage('<env>')
|
||||||
|
.description('build we chat mp of build on demand')
|
||||||
|
.action(build_1.default);
|
||||||
|
commander_1.default
|
||||||
|
.command('create <name> [env]')
|
||||||
|
.usage('<name>')
|
||||||
|
// .option('-e, --env <env>', 'A env')
|
||||||
|
.description(`create a new project powered by ${config_1.CLI_NAME}`)
|
||||||
|
.action(create_1.default);
|
||||||
|
// output help information on unknown commands
|
||||||
|
commander_1.default.arguments('<command>').action((cmd) => {
|
||||||
|
commander_1.default.outputHelp();
|
||||||
|
console.log();
|
||||||
|
console.log(` ` + `${(0, tip_style_1.error)(`Unknown command ${(0, tip_style_1.warn)(cmd)}`)}`);
|
||||||
|
console.log();
|
||||||
|
});
|
||||||
|
enhanceErrorMessages('missingArgument', (argName) => {
|
||||||
|
console.log();
|
||||||
|
return `${(0, tip_style_1.error)(`Missing required argument ${(0, tip_style_1.warn)(argName)}.`)}`;
|
||||||
|
});
|
||||||
|
commander_1.default.parse(process.argv);
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
/**
|
||||||
|
* @name 生成package.json需要输入的参数
|
||||||
|
* @export
|
||||||
|
* @interface PackageJsonInput
|
||||||
|
*/
|
||||||
|
export interface PackageJsonInput {
|
||||||
|
name: string;
|
||||||
|
version?: string;
|
||||||
|
description?: string;
|
||||||
|
cliversion: string;
|
||||||
|
cliname: string;
|
||||||
|
isDev?: boolean;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @name Prompt需要输入的参数
|
||||||
|
* @export
|
||||||
|
* @interface PromptInput
|
||||||
|
*/
|
||||||
|
export interface PromptInput {
|
||||||
|
name: string;
|
||||||
|
version: string;
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @name project.config.json
|
||||||
|
* @export
|
||||||
|
* @interface ProjectConfigInterface
|
||||||
|
*/
|
||||||
|
export interface ProjectConfigInterface {
|
||||||
|
packOptions: PackOptions;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @name project.config.json PackOptions
|
||||||
|
* @export
|
||||||
|
* @interface PackOptions
|
||||||
|
*/
|
||||||
|
export interface PackOptions {
|
||||||
|
ignore: Array<PackOptionsIgnore>;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @name project.config.json PackOptions PackOptionsIgnore
|
||||||
|
* @export
|
||||||
|
* @interface PackOptionsIgnore
|
||||||
|
*/
|
||||||
|
export interface PackOptionsIgnore {
|
||||||
|
type: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @name oak-cli需要输入的参数
|
||||||
|
* @export
|
||||||
|
* @interface OakInput
|
||||||
|
*/
|
||||||
|
export interface OakInput {
|
||||||
|
mode: string;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
export default function make(): Promise<void>;
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const tip_style_1 = require("./tip-style");
|
||||||
|
const cross_spawn_1 = __importDefault(require("cross-spawn"));
|
||||||
|
async function make() {
|
||||||
|
(0, tip_style_1.Success)(`${(0, tip_style_1.success)(`build oak app domain`)}`);
|
||||||
|
// ts-node scripts/build-app-domain & npm link ./app-domain
|
||||||
|
const result = cross_spawn_1.default.sync('ts-node', [require.resolve('../scripts/' + 'build-app-domain.js')], {
|
||||||
|
stdio: 'inherit',
|
||||||
|
shell: true,
|
||||||
|
});
|
||||||
|
// const result2 = spawn.sync('npm -v', [], { stdio: 'inherit', shell: true });
|
||||||
|
if (result.status === 0) {
|
||||||
|
(0, tip_style_1.Success)(`${(0, tip_style_1.success)(`build 执行完成`)}`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
(0, tip_style_1.Error)(`${(0, tip_style_1.error)(`build 执行失败`)}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
(0, tip_style_1.Success)(`${(0, tip_style_1.success)(`npm link oak app domain`)}`);
|
||||||
|
const isMac = process.platform === 'darwin';
|
||||||
|
const result2 = cross_spawn_1.default.sync(`${isMac ? 'sudo' : ''} npm`, [`link ${process.cwd()}/oak-app-domain`], {
|
||||||
|
stdio: 'inherit',
|
||||||
|
shell: true,
|
||||||
|
});
|
||||||
|
if (result2.status === 0) {
|
||||||
|
(0, tip_style_1.Success)(`${(0, tip_style_1.success)(`link 执行完成`)}`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
(0, tip_style_1.Error)(`${(0, tip_style_1.error)(`link 执行失败`)}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.default = make;
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { PackageJsonInput } from './interface';
|
||||||
|
export declare function packageJsonContent({ name, version, description, cliversion, cliname, isDev, }: PackageJsonInput): string;
|
||||||
|
export declare function tsConfigJsonContent(): string;
|
||||||
|
export declare function projectConfigContentWithWeChatMp(oakConfigName: string, projectname: string, miniVersion: string): string;
|
||||||
|
export declare function oakConfigContentWithWeChatMp(): string;
|
||||||
|
|
@ -0,0 +1,203 @@
|
||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.oakConfigContentWithWeChatMp = exports.projectConfigContentWithWeChatMp = exports.tsConfigJsonContent = exports.packageJsonContent = void 0;
|
||||||
|
function packageJsonContent({ name, version, description, cliversion, cliname, isDev, }) {
|
||||||
|
let oakPackageStr;
|
||||||
|
if (isDev) {
|
||||||
|
oakPackageStr = `"${cliname}": "file:../${cliname}",
|
||||||
|
"oak-domain": "file:../oak-domain",
|
||||||
|
"oak-frontend-base": "file:../oak-frontend-base",
|
||||||
|
"oak-general-business": "file:../oak-general-business",
|
||||||
|
"oak-memory-tree-store": "file:../oak-memory-tree-store",`;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
oakPackageStr = `"${cliname}": "^${cliversion}",
|
||||||
|
"oak-domain": "^1.0.0",
|
||||||
|
"oak-frontend-base": "^1.0.0",
|
||||||
|
"oak-general-business": "^1.0.0",
|
||||||
|
"oak-memory-tree-store": "^1.0.0",`;
|
||||||
|
}
|
||||||
|
return `{
|
||||||
|
"name": "${name}",
|
||||||
|
"version": "${version}",
|
||||||
|
"description": "${description}",
|
||||||
|
"scripts": {
|
||||||
|
"make:domain": "${cliname} make",
|
||||||
|
"start:mp": "${cliname} start development",
|
||||||
|
"build:mp": "${cliname} build production"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "",
|
||||||
|
"dependencies": {
|
||||||
|
"@reduxjs/toolkit": "^1.7.2",
|
||||||
|
"crypto-browserify": "^3.12.0",
|
||||||
|
"lodash": "^4.17.21"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/cli": "^7.12.13",
|
||||||
|
"@babel/core": "^7.12.13",
|
||||||
|
"@babel/plugin-proposal-class-properties": "^7.12.13",
|
||||||
|
"@babel/preset-env": "^7.12.13",
|
||||||
|
"@babel/preset-typescript": "^7.12.13",
|
||||||
|
"@types/assert": "^1.5.6",
|
||||||
|
"@types/fs-extra": "^9.0.13",
|
||||||
|
"@types/lodash": "^4.14.179",
|
||||||
|
"@types/mocha": "^8.2.0",
|
||||||
|
"@types/node": "^14.14.25",
|
||||||
|
"@types/react": "^17.0.2",
|
||||||
|
"@types/shelljs": "^0.8.11",
|
||||||
|
"@types/uuid": "^8.3.0",
|
||||||
|
"@types/wechat-miniprogram": "^3.4.0",
|
||||||
|
"assert": "^2.0.0",
|
||||||
|
"babel-loader": "^8.2.3",
|
||||||
|
"chalk": "^4.1.2",
|
||||||
|
"clean-webpack-plugin": "^4.0.0",
|
||||||
|
"copy-webpack-plugin": "^10.2.4",
|
||||||
|
"cross-env": "^7.0.2",
|
||||||
|
"css-loader": "^6.6.0",
|
||||||
|
"dotenv-webpack": "^7.1.0",
|
||||||
|
"ensure-posix-path": "^1.1.1",
|
||||||
|
"file-loader": "^6.2.0",
|
||||||
|
"fs-extra": "^10.0.0",
|
||||||
|
"globby": "^11.1.0",
|
||||||
|
"less-loader": "^10.2.0",
|
||||||
|
"mini-css-extract-plugin": "^2.5.3",
|
||||||
|
"miniprogram-api-typings": "^3.4.5",
|
||||||
|
"mocha": "^8.2.1",
|
||||||
|
${oakPackageStr}
|
||||||
|
"postcss-less": "^6.0.0",
|
||||||
|
"progress": "^2.0.3",
|
||||||
|
"progress-bar-webpack-plugin": "^2.1.0",
|
||||||
|
"required-path": "^1.0.1",
|
||||||
|
"shelljs": "^0.8.5",
|
||||||
|
"style-loader": "^3.3.1",
|
||||||
|
"stylelint-config-standard": "^25.0.0",
|
||||||
|
"stylelint-webpack-plugin": "^3.1.1",
|
||||||
|
"ts-loader": "^9.2.6",
|
||||||
|
"ts-node": "^9.1.1",
|
||||||
|
"typescript": "^4.5.2",
|
||||||
|
"ui-extract-webpack-plugin": "^1.0.0",
|
||||||
|
"webpack": "^5.69.1",
|
||||||
|
"webpack-dashboard": "^3.3.7"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
exports.packageJsonContent = packageJsonContent;
|
||||||
|
function tsConfigJsonContent() {
|
||||||
|
return `{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "CommonJS",
|
||||||
|
"target": "esnext",
|
||||||
|
"allowJs": false,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"strict": true,
|
||||||
|
"lib": [
|
||||||
|
"ES2020"
|
||||||
|
],
|
||||||
|
"typeRoots": [
|
||||||
|
"./src/typings"
|
||||||
|
],
|
||||||
|
"types": [
|
||||||
|
"node",
|
||||||
|
"miniprogram-api-typings"
|
||||||
|
],
|
||||||
|
"resolveJsonModule": true /* Disallow inconsistently-cased references to the same file. */
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"./**/*.ts",
|
||||||
|
"scripts/webpack.js"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
]
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
exports.tsConfigJsonContent = tsConfigJsonContent;
|
||||||
|
function projectConfigContentWithWeChatMp(oakConfigName, projectname, miniVersion) {
|
||||||
|
return `{
|
||||||
|
"description": "项目配置文件",
|
||||||
|
"packOptions": {
|
||||||
|
"ignore": [{
|
||||||
|
"type": "file",
|
||||||
|
"value": "${oakConfigName}"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"setting": {
|
||||||
|
"urlCheck": true,
|
||||||
|
"es6": true,
|
||||||
|
"enhance": true,
|
||||||
|
"postcss": true,
|
||||||
|
"preloadBackgroundData": false,
|
||||||
|
"minified": true,
|
||||||
|
"newFeature": false,
|
||||||
|
"coverView": true,
|
||||||
|
"nodeModules": true,
|
||||||
|
"autoAudits": false,
|
||||||
|
"showShadowRootInWxmlPanel": true,
|
||||||
|
"scopeDataCheck": false,
|
||||||
|
"uglifyFileName": false,
|
||||||
|
"checkInvalidKey": true,
|
||||||
|
"checkSiteMap": true,
|
||||||
|
"uploadWithSourceMap": true,
|
||||||
|
"compileHotReLoad": false,
|
||||||
|
"babelSetting": {
|
||||||
|
"ignore": [],
|
||||||
|
"disablePlugins": [],
|
||||||
|
"outputPath": ""
|
||||||
|
},
|
||||||
|
"useIsolateContext": true,
|
||||||
|
"useCompilerModule": false,
|
||||||
|
"userConfirmedUseCompilerModuleSwitch": false
|
||||||
|
},
|
||||||
|
"compileType": "miniprogram",
|
||||||
|
"libVersion": "${miniVersion}",
|
||||||
|
"appid": "",
|
||||||
|
"projectname": "${projectname}",
|
||||||
|
"debugOptions": {
|
||||||
|
"hidedInDevtools": []
|
||||||
|
},
|
||||||
|
"scripts": "",
|
||||||
|
"isGameTourist": false,
|
||||||
|
"simulatorType": "wechat",
|
||||||
|
"simulatorPluginLibVersion": {},
|
||||||
|
"condition": {
|
||||||
|
"search": {
|
||||||
|
"current": -1,
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
|
"conversation": {
|
||||||
|
"current": -1,
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
|
"game": {
|
||||||
|
"current": -1,
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
|
"plugin": {
|
||||||
|
"current": -1,
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
|
"gamePlugin": {
|
||||||
|
"current": -1,
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
|
"miniprogram": {
|
||||||
|
"current": -1,
|
||||||
|
"list": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
exports.projectConfigContentWithWeChatMp = projectConfigContentWithWeChatMp;
|
||||||
|
function oakConfigContentWithWeChatMp() {
|
||||||
|
return `{
|
||||||
|
"theme": {
|
||||||
|
"@primary-color": "#2d8cf0"
|
||||||
|
}
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
exports.oakConfigContentWithWeChatMp = oakConfigContentWithWeChatMp;
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
export declare const Success: (content: any) => void;
|
||||||
|
export declare const Error: (content: any) => void;
|
||||||
|
export declare const Start: (content: any) => void;
|
||||||
|
export declare const Warn: (content: any) => void;
|
||||||
|
export declare const success: (content: any) => string;
|
||||||
|
export declare const error: (content: any) => string;
|
||||||
|
export declare const primary: (content: any) => string;
|
||||||
|
export declare const warn: (content: any) => string;
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.warn = exports.primary = exports.error = exports.success = exports.Warn = exports.Start = exports.Error = exports.Success = void 0;
|
||||||
|
const chalk_1 = __importDefault(require("chalk"));
|
||||||
|
const consola_1 = __importDefault(require("consola"));
|
||||||
|
// tip type
|
||||||
|
const Success = (content) => consola_1.default.success(content);
|
||||||
|
exports.Success = Success;
|
||||||
|
const Error = (content) => consola_1.default.error(content);
|
||||||
|
exports.Error = Error;
|
||||||
|
const Start = (content) => consola_1.default.start(content);
|
||||||
|
exports.Start = Start;
|
||||||
|
const Warn = (content) => consola_1.default.warn(content);
|
||||||
|
exports.Warn = Warn;
|
||||||
|
// tip style
|
||||||
|
const success = (content) => chalk_1.default.greenBright(content);
|
||||||
|
exports.success = success;
|
||||||
|
const error = (content) => chalk_1.default.redBright(content);
|
||||||
|
exports.error = error;
|
||||||
|
const primary = (content) => chalk_1.default.blueBright(content);
|
||||||
|
exports.primary = primary;
|
||||||
|
const warn = (content) => chalk_1.default.yellowBright(content);
|
||||||
|
exports.warn = warn;
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
/**
|
||||||
|
* @name 从一组路径里查找到所有json文件
|
||||||
|
* @export
|
||||||
|
* @param {Array<string>} pathArr
|
||||||
|
* @returns {Set<string>}
|
||||||
|
*/
|
||||||
|
export declare function findJson(pathArr: Set<string>): Set<string>;
|
||||||
|
/**
|
||||||
|
* @name 已知前后文取中间文本
|
||||||
|
* @export
|
||||||
|
* @param {string} str
|
||||||
|
* @param {string} start
|
||||||
|
* @param {string} end
|
||||||
|
* @returns {(string | null)}
|
||||||
|
*/
|
||||||
|
export declare function getStr(str: string, start: string, end: string): string | null;
|
||||||
|
/**
|
||||||
|
* @name 差集
|
||||||
|
* @export
|
||||||
|
* @template T
|
||||||
|
* @param {Set<T>} current
|
||||||
|
* @param {Set<T>} target
|
||||||
|
* @returns {Set<T>}
|
||||||
|
*/
|
||||||
|
export declare function difference<T>(current: Set<T>, target: Set<T>): Set<T>;
|
||||||
|
/**
|
||||||
|
* @name 获取交集
|
||||||
|
* @export
|
||||||
|
* @template T
|
||||||
|
* @param {Set<T>} current
|
||||||
|
* @param {Set<T>} target
|
||||||
|
* @returns {Set<T>}
|
||||||
|
*/
|
||||||
|
export declare function intersect<T>(current: Set<T>, target: Set<T>): Set<T>;
|
||||||
|
/**
|
||||||
|
* @name 获取并集
|
||||||
|
* @export
|
||||||
|
* @template T
|
||||||
|
* @param {Set<T>} current
|
||||||
|
* @param {Set<T>} target
|
||||||
|
* @returns {Set<T>}
|
||||||
|
*/
|
||||||
|
export declare function union<T>(current: Set<T>, target: Set<T>): Set<T>;
|
||||||
|
/**
|
||||||
|
* @name 格式化json
|
||||||
|
* @export
|
||||||
|
* @template T
|
||||||
|
* @param {T} data
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
export declare function formatJsonByFile<T extends Object>(data: T): string;
|
||||||
|
/**
|
||||||
|
* @name 数组对象去重
|
||||||
|
* @export
|
||||||
|
* @param {Array<any>} arr 需要去重的数组或set
|
||||||
|
* @param {*} [type] 需要根据哪个字段去重
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export declare function deWeight(arr: Array<any> | Set<any>, type: any): Set<any>;
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.deWeight = exports.formatJsonByFile = exports.union = exports.intersect = exports.difference = exports.getStr = exports.findJson = void 0;
|
||||||
|
/**
|
||||||
|
* @name 从一组路径里查找到所有json文件
|
||||||
|
* @export
|
||||||
|
* @param {Array<string>} pathArr
|
||||||
|
* @returns {Set<string>}
|
||||||
|
*/
|
||||||
|
function findJson(pathArr) {
|
||||||
|
const result = new Set();
|
||||||
|
for (let item of pathArr) {
|
||||||
|
const endIndex = item.length;
|
||||||
|
const str = item.substring(endIndex - 5, endIndex);
|
||||||
|
if (str === '.json') {
|
||||||
|
result.add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
exports.findJson = findJson;
|
||||||
|
/**
|
||||||
|
* @name 已知前后文取中间文本
|
||||||
|
* @export
|
||||||
|
* @param {string} str
|
||||||
|
* @param {string} start
|
||||||
|
* @param {string} end
|
||||||
|
* @returns {(string | null)}
|
||||||
|
*/
|
||||||
|
function getStr(str, start, end) {
|
||||||
|
const reg = new RegExp(`${start}(.*?)${end}`);
|
||||||
|
let res = str.match(reg);
|
||||||
|
return res ? res[1] : null;
|
||||||
|
}
|
||||||
|
exports.getStr = getStr;
|
||||||
|
/**
|
||||||
|
* @name 差集
|
||||||
|
* @export
|
||||||
|
* @template T
|
||||||
|
* @param {Set<T>} current
|
||||||
|
* @param {Set<T>} target
|
||||||
|
* @returns {Set<T>}
|
||||||
|
*/
|
||||||
|
function difference(current, target) {
|
||||||
|
return new Set([...target].filter(x => !current.has(x)));
|
||||||
|
}
|
||||||
|
exports.difference = difference;
|
||||||
|
/**
|
||||||
|
* @name 获取交集
|
||||||
|
* @export
|
||||||
|
* @template T
|
||||||
|
* @param {Set<T>} current
|
||||||
|
* @param {Set<T>} target
|
||||||
|
* @returns {Set<T>}
|
||||||
|
*/
|
||||||
|
function intersect(current, target) {
|
||||||
|
return new Set([...target].filter(x => current.has(x)));
|
||||||
|
}
|
||||||
|
exports.intersect = intersect;
|
||||||
|
/**
|
||||||
|
* @name 获取并集
|
||||||
|
* @export
|
||||||
|
* @template T
|
||||||
|
* @param {Set<T>} current
|
||||||
|
* @param {Set<T>} target
|
||||||
|
* @returns {Set<T>}
|
||||||
|
*/
|
||||||
|
function union(current, target) {
|
||||||
|
return new Set([...current, ...target]);
|
||||||
|
}
|
||||||
|
exports.union = union;
|
||||||
|
/**
|
||||||
|
* @name 格式化json
|
||||||
|
* @export
|
||||||
|
* @template T
|
||||||
|
* @param {T} data
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function formatJsonByFile(data) {
|
||||||
|
return JSON.stringify(data, null, 2);
|
||||||
|
}
|
||||||
|
exports.formatJsonByFile = formatJsonByFile;
|
||||||
|
/**
|
||||||
|
* @name 数组对象去重
|
||||||
|
* @export
|
||||||
|
* @param {Array<any>} arr 需要去重的数组或set
|
||||||
|
* @param {*} [type] 需要根据哪个字段去重
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function deWeight(arr, type) {
|
||||||
|
let map = new Map();
|
||||||
|
for (let item of arr) {
|
||||||
|
if (!map.has(item[type])) {
|
||||||
|
map.set(item[type], item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new Set([...map.values()]);
|
||||||
|
}
|
||||||
|
exports.deWeight = deWeight;
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
{
|
||||||
|
"name": "oak-cli",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "oak-cli脚手架",
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"dev": "tsc --watch"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"oak-cli": "lib/index.js"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "",
|
||||||
|
"bugs": {
|
||||||
|
"url": ""
|
||||||
|
},
|
||||||
|
"homepage": "",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/cross-spawn": "^6.0.2",
|
||||||
|
"@types/inquirer": "^7.3.1",
|
||||||
|
"@types/node": "^12.0.27",
|
||||||
|
"@types/shelljs": "^0.8.8"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": ">=0.21.1",
|
||||||
|
"chalk": "^4.1.0",
|
||||||
|
"clean-webpack-plugin": "^4.0.0",
|
||||||
|
"commander": "^6.0.0",
|
||||||
|
"consola": "^2.15.0",
|
||||||
|
"copy-webpack-plugin": "^10.2.4",
|
||||||
|
"cross-spawn": "^6.0.5",
|
||||||
|
"crypto-browserify": "^3.12.0",
|
||||||
|
"dotenv-webpack": "^7.1.0",
|
||||||
|
"ensure-posix-path": "^1.1.1",
|
||||||
|
"fs-extra": "^10.0.0",
|
||||||
|
"globby": "^11.1.0",
|
||||||
|
"inquirer": "^7.3.3",
|
||||||
|
"mini-css-extract-plugin": "^2.5.3",
|
||||||
|
"postcss-less": "^6.0.0",
|
||||||
|
"progress-bar-webpack-plugin": "^2.1.0",
|
||||||
|
"required-path": "^1.0.1",
|
||||||
|
"shelljs": "^0.8.4",
|
||||||
|
"stylelint-webpack-plugin": "^3.2.0",
|
||||||
|
"ui-extract-webpack-plugin": "^1.0.0",
|
||||||
|
"webpack": "^5.72.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,595 @@
|
||||||
|
/**
|
||||||
|
* 把目录下所有的.ts和.less文件加入entry
|
||||||
|
*/
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const fsExtra = require('fs-extra');
|
||||||
|
const globby = require('globby');
|
||||||
|
const { optimize, sources } = require('webpack');
|
||||||
|
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||||
|
// const LoaderTargetPlugin = require('webpack/lib/LoaderTargetPlugin');
|
||||||
|
// const NodeSourcePlugin = require('webpack/lib/node/NodeSourcePlugin');
|
||||||
|
// const JsonpTemplatePlugin = require('webpack/lib/web/JsonpTemplatePlugin');
|
||||||
|
const JavascriptModulesPlugin = require('webpack/lib/javascript/JavascriptModulesPlugin');
|
||||||
|
const EntryPlugin = require('webpack/lib/EntryPlugin');
|
||||||
|
const ensurePosix = require('ensure-posix-path');
|
||||||
|
const requiredPath = require('required-path');
|
||||||
|
|
||||||
|
const pluginName = 'OakWeChatMpPlugin';
|
||||||
|
const oakPagePrefix = 'oak#';
|
||||||
|
const oakPagePath = 'node_modules/oak-general-business/src/platforms/wechatMp/';
|
||||||
|
// const oakPagePathRegExp = /node_modules\/oak-general-business\/src\/platforms\/wechatMp\//;
|
||||||
|
|
||||||
|
function getIsOak(str) {
|
||||||
|
return str.indexOf(oakPagePrefix) === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
class OakWeChatMpPlugin {
|
||||||
|
constructor(options = {}) {
|
||||||
|
this.options = Object.assign(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
clear: true,
|
||||||
|
extensions: ['.js', '.ts'], // script ext
|
||||||
|
include: [], // include assets file
|
||||||
|
exclude: [], // ignore assets file
|
||||||
|
assetsChunkName: '__assets_chunk__',
|
||||||
|
commonsChunkName: 'commons',
|
||||||
|
vendorChunkName: 'vendor',
|
||||||
|
runtimeChunkName: 'runtime',
|
||||||
|
},
|
||||||
|
options
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
apply(compiler) {
|
||||||
|
this.setBasePath(compiler);
|
||||||
|
|
||||||
|
const catchError = (handler) => async (arg) => {
|
||||||
|
try {
|
||||||
|
await handler(arg);
|
||||||
|
} catch (err) {
|
||||||
|
console.warn(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.firstClean = false;
|
||||||
|
|
||||||
|
compiler.hooks.run.tapPromise(
|
||||||
|
pluginName,
|
||||||
|
catchError((compiler) => this.setAppEntries(compiler))
|
||||||
|
);
|
||||||
|
|
||||||
|
compiler.hooks.watchRun.tapPromise(
|
||||||
|
pluginName,
|
||||||
|
catchError((compiler) => this.setAppEntries(compiler))
|
||||||
|
);
|
||||||
|
|
||||||
|
compiler.hooks.compilation.tap(
|
||||||
|
pluginName,
|
||||||
|
catchError((compilation) => this.compilationHooks(compilation))
|
||||||
|
);
|
||||||
|
|
||||||
|
compiler.hooks.emit.tapPromise(
|
||||||
|
pluginName,
|
||||||
|
catchError(async (compilation) => {
|
||||||
|
const { clear } = this.options;
|
||||||
|
if (clear && !this.firstClean) {
|
||||||
|
this.firstClean = true;
|
||||||
|
await OakWeChatMpPlugin.clearOutPut(compilation);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
compilationHooks(compilation) {
|
||||||
|
const { assetsChunkName } = this.options;
|
||||||
|
|
||||||
|
JavascriptModulesPlugin.getCompilationHooks(compilation).render.tap(
|
||||||
|
pluginName,
|
||||||
|
(source, { chunkGraph, chunk }) => {
|
||||||
|
// 非动态入口
|
||||||
|
const hasEntryModule =
|
||||||
|
chunkGraph.getNumberOfEntryModules(chunk) > 0;
|
||||||
|
if (!hasEntryModule) return source;
|
||||||
|
// 收集动态入口所有的依赖
|
||||||
|
let dependences = [];
|
||||||
|
[...chunk.groupsIterable].forEach((group) => {
|
||||||
|
[...group.chunks].forEach((chunk2) => {
|
||||||
|
const filename = ensurePosix(
|
||||||
|
path.relative(path.dirname(chunk.name), chunk2.name)
|
||||||
|
);
|
||||||
|
// console.log(filename)
|
||||||
|
if (
|
||||||
|
chunk === chunk2 ||
|
||||||
|
dependences.includes(filename)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dependences.push(filename);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// 没有依赖
|
||||||
|
if (dependences.length == 0) return;
|
||||||
|
// 源文件拼接依赖
|
||||||
|
const concatStr = dependences.reduce((prev, file) => {
|
||||||
|
prev += `require('${requiredPath(file)}');`;
|
||||||
|
return prev;
|
||||||
|
}, ';');
|
||||||
|
return new sources.ConcatSource(concatStr, source);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// splice assets module
|
||||||
|
compilation.hooks.beforeChunkAssets.tap(pluginName, () => {
|
||||||
|
let assetsChunk;
|
||||||
|
compilation.chunks.forEach((chunk) => {
|
||||||
|
if (chunk.name === assetsChunkName) {
|
||||||
|
assetsChunk = chunk;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (assetsChunk) {
|
||||||
|
compilation.chunks.delete(assetsChunk);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
compilation.hooks.processAssets.tapPromise(
|
||||||
|
{
|
||||||
|
name: pluginName,
|
||||||
|
stage: compilation.PROCESS_ASSETS_STAGE_ADDITIONAL,
|
||||||
|
},
|
||||||
|
async (assets) => {
|
||||||
|
await this.emitAssetsFile(compilation);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async setAppEntries(compiler) {
|
||||||
|
this.npmComponents = new Set();
|
||||||
|
this.oakPages = new Set();
|
||||||
|
this.oakComponents = new Set();
|
||||||
|
this.appEntries = await this.resolveAppEntries(compiler);
|
||||||
|
await Promise.all([
|
||||||
|
this.addScriptEntry(compiler),
|
||||||
|
this.addAssetsEntries(compiler),
|
||||||
|
]);
|
||||||
|
this.applyPlugin(compiler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolve tabbar page compoments
|
||||||
|
async resolveAppEntries(compiler) {
|
||||||
|
const {
|
||||||
|
tabBar = {},
|
||||||
|
pages = [],
|
||||||
|
subpackages = [],
|
||||||
|
} = fsExtra.readJSONSync(path.join(this.basePath, 'app.json'));
|
||||||
|
|
||||||
|
let tabBarAssets = new Set();
|
||||||
|
let components = new Set();
|
||||||
|
let subPageRoots = [];
|
||||||
|
let independentPageRoots = [];
|
||||||
|
let realPages = [];
|
||||||
|
this.subpackRoot = [];
|
||||||
|
|
||||||
|
for (const { iconPath, selectedIconPath } of tabBar.list || []) {
|
||||||
|
if (iconPath) {
|
||||||
|
tabBarAssets.add(iconPath);
|
||||||
|
}
|
||||||
|
if (selectedIconPath) {
|
||||||
|
tabBarAssets.add(selectedIconPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse subpage
|
||||||
|
for (const subPage of subpackages) {
|
||||||
|
subPageRoots.push(subPage.root);
|
||||||
|
if (subPage.independent) {
|
||||||
|
independentPageRoots.push(subPage.root);
|
||||||
|
}
|
||||||
|
for (const page of subPage.pages || []) {
|
||||||
|
realPages.push(path.join(subPage.root, page));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add app.[ts/js]
|
||||||
|
realPages.push('app');
|
||||||
|
// resolve page components
|
||||||
|
for (const page of pages) {
|
||||||
|
let instance;
|
||||||
|
let isOak = getIsOak(page);
|
||||||
|
if (isOak) {
|
||||||
|
const oakPage = page.replace(
|
||||||
|
new RegExp(oakPagePrefix),
|
||||||
|
oakPagePath
|
||||||
|
);
|
||||||
|
instance = path.resolve(process.cwd(), oakPage);
|
||||||
|
if (!this.oakPages.has(oakPage)) {
|
||||||
|
this.oakPages.add(oakPage);
|
||||||
|
realPages.push(oakPage);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
realPages.push(page);
|
||||||
|
instance = path.resolve(this.basePath, page);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.getComponents(components, instance, isOak);
|
||||||
|
}
|
||||||
|
|
||||||
|
components = Array.from(components) || [];
|
||||||
|
tabBarAssets = Array.from(tabBarAssets) || [];
|
||||||
|
|
||||||
|
const ret = [...realPages, ...components];
|
||||||
|
|
||||||
|
Object.defineProperties(ret, {
|
||||||
|
pages: {
|
||||||
|
get: () => realPages,
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
get: () => components,
|
||||||
|
},
|
||||||
|
tabBarAssets: {
|
||||||
|
get: () => tabBarAssets,
|
||||||
|
},
|
||||||
|
subPageRoots: {
|
||||||
|
get: () => subPageRoots,
|
||||||
|
},
|
||||||
|
independentPageRoots: {
|
||||||
|
get: () => independentPageRoots,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse components
|
||||||
|
async getComponents(components, instance, isOak) {
|
||||||
|
try {
|
||||||
|
const { usingComponents = {} } = fsExtra.readJSONSync(
|
||||||
|
`${instance}.json`
|
||||||
|
);
|
||||||
|
const instanceDir = path.parse(instance).dir;
|
||||||
|
for (const c of Object.values(usingComponents)) {
|
||||||
|
if (c.indexOf('plugin://') === 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (c.indexOf('/miniprogram_npm') === 0) {
|
||||||
|
const component = c.replace(
|
||||||
|
/\/miniprogram_npm/,
|
||||||
|
'node_modules'
|
||||||
|
);
|
||||||
|
if (!this.npmComponents.has(component)) {
|
||||||
|
this.npmComponents.add(component);
|
||||||
|
components.add(component);
|
||||||
|
this.getComponents(
|
||||||
|
components,
|
||||||
|
path.resolve(process.cwd(), component)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (isOak) {
|
||||||
|
const component = path
|
||||||
|
.resolve(instanceDir, c)
|
||||||
|
.replace(/\\/g, '/');
|
||||||
|
const component2 = component.replace(
|
||||||
|
process.cwd() + '/',
|
||||||
|
''
|
||||||
|
);
|
||||||
|
if (!this.oakComponents.has(component2)) {
|
||||||
|
this.oakComponents.add(component2);
|
||||||
|
components.add(component2);
|
||||||
|
await this.getComponents(
|
||||||
|
components,
|
||||||
|
path.resolve(process.cwd(), component2),
|
||||||
|
isOak
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const component = path
|
||||||
|
.resolve(instanceDir, c)
|
||||||
|
.replace(/\\/g, '/');
|
||||||
|
if (!components.has(component)) {
|
||||||
|
// components.add(path.relative(this.basePath, component));
|
||||||
|
// await this.getComponents(components, component);
|
||||||
|
const component2 = path
|
||||||
|
.relative(this.basePath, component)
|
||||||
|
.replace(/\\/g, '/');
|
||||||
|
if (!components.has(component2)) {
|
||||||
|
components.add(component2);
|
||||||
|
await this.getComponents(components, component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add script entry
|
||||||
|
async addScriptEntry(compiler) {
|
||||||
|
this.appEntries
|
||||||
|
.filter((resource) => resource !== 'app')
|
||||||
|
.forEach((resource) => {
|
||||||
|
if (this.npmComponents.has(resource)) {
|
||||||
|
new EntryPlugin(
|
||||||
|
this.basePath,
|
||||||
|
path.join(process.cwd(), resource),
|
||||||
|
resource.replace(/node_modules/, 'miniprogram_npm')
|
||||||
|
).apply(compiler);
|
||||||
|
} else if (this.oakPages.has(resource)) {
|
||||||
|
new EntryPlugin(
|
||||||
|
this.basePath,
|
||||||
|
path.join(process.cwd(), resource),
|
||||||
|
resource.replace(new RegExp(oakPagePath), '')
|
||||||
|
).apply(compiler);
|
||||||
|
} else if (this.oakComponents.has(resource)) {
|
||||||
|
new EntryPlugin(
|
||||||
|
this.basePath,
|
||||||
|
path.join(process.cwd(), resource),
|
||||||
|
resource.replace(new RegExp(oakPagePath), '')
|
||||||
|
).apply(compiler);
|
||||||
|
} else {
|
||||||
|
const fullPath = this.getFullScriptPath(resource);
|
||||||
|
if (fullPath) {
|
||||||
|
new EntryPlugin(
|
||||||
|
this.basePath,
|
||||||
|
fullPath,
|
||||||
|
resource
|
||||||
|
).apply(compiler);
|
||||||
|
} else {
|
||||||
|
console.warn(`file ${resource} is exists`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// add assets entry
|
||||||
|
async addAssetsEntries(compiler) {
|
||||||
|
const { include, exclude, extensions, assetsChunkName } = this.options;
|
||||||
|
const patterns = this.appEntries
|
||||||
|
.map((resource) => `${resource}.*`)
|
||||||
|
.concat(include);
|
||||||
|
const entries = await globby(patterns, {
|
||||||
|
cwd: this.basePath,
|
||||||
|
nodir: true,
|
||||||
|
realpath: false,
|
||||||
|
ignore: [...extensions.map((ext) => `**/*${ext}`), ...exclude],
|
||||||
|
dot: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.assetsEntry = [...entries, ...this.appEntries.tabBarAssets];
|
||||||
|
this.assetsEntry.forEach((resource) => {
|
||||||
|
new EntryPlugin(
|
||||||
|
this.basePath,
|
||||||
|
path.resolve(this.basePath, resource),
|
||||||
|
assetsChunkName
|
||||||
|
).apply(compiler);
|
||||||
|
});
|
||||||
|
|
||||||
|
const oakPageAssetsEntry = await globby(
|
||||||
|
[...this.oakPages]
|
||||||
|
.map((resource) => `${path.parse(resource).dir}/**/*.*`)
|
||||||
|
.concat(include),
|
||||||
|
{
|
||||||
|
cwd: process.cwd(),
|
||||||
|
nodir: true,
|
||||||
|
realpath: false,
|
||||||
|
ignore: [...extensions.map((ext) => `**/*${ext}`), ...exclude],
|
||||||
|
dot: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const oakComponentAssetsEntry = await globby(
|
||||||
|
[...this.oakComponents]
|
||||||
|
.map((resource) => `${path.parse(resource).dir}/**/*.*`)
|
||||||
|
.concat(include),
|
||||||
|
{
|
||||||
|
cwd: process.cwd(),
|
||||||
|
nodir: true,
|
||||||
|
realpath: false,
|
||||||
|
ignore: [...extensions.map((ext) => `**/*${ext}`), ...exclude],
|
||||||
|
dot: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this.oakAssetsEntry = [
|
||||||
|
...oakPageAssetsEntry,
|
||||||
|
...oakComponentAssetsEntry,
|
||||||
|
];
|
||||||
|
this.oakAssetsEntry.forEach((resource) => {
|
||||||
|
new EntryPlugin(
|
||||||
|
this.basePath,
|
||||||
|
path.resolve(process.cwd(), resource),
|
||||||
|
assetsChunkName
|
||||||
|
).apply(compiler);
|
||||||
|
});
|
||||||
|
|
||||||
|
const npmAssetsEntry = await globby(
|
||||||
|
[...this.npmComponents]
|
||||||
|
.map((resource) => `${path.parse(resource).dir}/**/*.*`)
|
||||||
|
.concat(include),
|
||||||
|
{
|
||||||
|
cwd: process.cwd(),
|
||||||
|
nodir: true,
|
||||||
|
realpath: false,
|
||||||
|
ignore: [...extensions.map((ext) => `**/*${ext}`), ...exclude],
|
||||||
|
dot: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (npmAssetsEntry.length > 0) {
|
||||||
|
new CopyWebpackPlugin({
|
||||||
|
patterns: [
|
||||||
|
...npmAssetsEntry.map((resource) => {
|
||||||
|
return {
|
||||||
|
from: path.resolve(
|
||||||
|
process.cwd().replace(/\\/g, '/'),
|
||||||
|
resource
|
||||||
|
),
|
||||||
|
to: resource.replace(
|
||||||
|
/node_modules/,
|
||||||
|
'miniprogram_npm'
|
||||||
|
),
|
||||||
|
globOptions: {
|
||||||
|
ignore: [
|
||||||
|
...extensions.map((ext) => `**/*${ext}`),
|
||||||
|
...exclude,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}).apply(compiler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// code splite
|
||||||
|
applyPlugin(compiler) {
|
||||||
|
const { runtimeChunkName, commonsChunkName, vendorChunkName } =
|
||||||
|
this.options;
|
||||||
|
const subpackRoots = this.appEntries.subPageRoots;
|
||||||
|
const independentPageRoots = this.appEntries.independentPageRoots;
|
||||||
|
|
||||||
|
new optimize.RuntimeChunkPlugin({
|
||||||
|
name({ name }) {
|
||||||
|
const index = independentPageRoots.findIndex((item) =>
|
||||||
|
name.includes(item)
|
||||||
|
);
|
||||||
|
if (index !== -1) {
|
||||||
|
return path.join(
|
||||||
|
independentPageRoots[index],
|
||||||
|
runtimeChunkName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return runtimeChunkName;
|
||||||
|
},
|
||||||
|
}).apply(compiler);
|
||||||
|
|
||||||
|
new optimize.SplitChunksPlugin({
|
||||||
|
hidePathInfo: false,
|
||||||
|
chunks: 'async',
|
||||||
|
minSize: 10000,
|
||||||
|
minChunks: 1,
|
||||||
|
maxAsyncRequests: Infinity,
|
||||||
|
automaticNameDelimiter: '~',
|
||||||
|
maxInitialRequests: Infinity,
|
||||||
|
name: true,
|
||||||
|
cacheGroups: {
|
||||||
|
default: false,
|
||||||
|
// node_modules
|
||||||
|
vendor: {
|
||||||
|
chunks: 'all',
|
||||||
|
test: /[\\/]node_modules[\\/]/,
|
||||||
|
name: vendorChunkName,
|
||||||
|
minChunks: 0,
|
||||||
|
},
|
||||||
|
// 其他公用代码
|
||||||
|
common: {
|
||||||
|
chunks: 'all',
|
||||||
|
test: /[\\/]src[\\/]/,
|
||||||
|
minChunks: 2,
|
||||||
|
name({ context }) {
|
||||||
|
const index = subpackRoots.findIndex((item) =>
|
||||||
|
context.includes(item)
|
||||||
|
);
|
||||||
|
if (index !== -1) {
|
||||||
|
return path.join(
|
||||||
|
subpackRoots[index],
|
||||||
|
commonsChunkName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return commonsChunkName;
|
||||||
|
},
|
||||||
|
minSize: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}).apply(compiler);
|
||||||
|
}
|
||||||
|
|
||||||
|
async emitAssetsFile(compilation) {
|
||||||
|
const emitAssets = [];
|
||||||
|
for (let entry of this.assetsEntry) {
|
||||||
|
const assets = path.resolve(this.basePath, entry);
|
||||||
|
if (/\.(sass|scss|css|less|styl)$/.test(assets)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const toTmit = async () => {
|
||||||
|
const stat = await fsExtra.stat(assets);
|
||||||
|
let size = stat.size;
|
||||||
|
let source = await fsExtra.readFile(assets);
|
||||||
|
if (entry === 'app.json') {
|
||||||
|
const appJson = JSON.parse(source.toString());
|
||||||
|
|
||||||
|
let pages = [];
|
||||||
|
for (let page of appJson.pages) {
|
||||||
|
let isOak = getIsOak(page);
|
||||||
|
|
||||||
|
if (isOak) {
|
||||||
|
page = page.replace(new RegExp(oakPagePrefix), '');
|
||||||
|
}
|
||||||
|
pages.push(page);
|
||||||
|
}
|
||||||
|
appJson.pages = pages;
|
||||||
|
source = Buffer.from(JSON.stringify(appJson, null, 2));
|
||||||
|
size = source.length;
|
||||||
|
}
|
||||||
|
compilation.assets[entry] = {
|
||||||
|
size: () => size,
|
||||||
|
source: () => source,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
emitAssets.push(toTmit());
|
||||||
|
}
|
||||||
|
for (let entry of this.oakAssetsEntry) {
|
||||||
|
const assets = path.resolve(process.cwd(), entry);
|
||||||
|
if (/\.(sass|scss|css|less|styl)$/.test(assets)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const toTmit = async () => {
|
||||||
|
const stat = await fsExtra.stat(assets);
|
||||||
|
const source = await fsExtra.readFile(assets);
|
||||||
|
compilation.assets[entry.replace(new RegExp(oakPagePath), '')] =
|
||||||
|
{
|
||||||
|
size: () => stat.size,
|
||||||
|
source: () => source,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
emitAssets.push(toTmit());
|
||||||
|
}
|
||||||
|
await Promise.all(emitAssets);
|
||||||
|
}
|
||||||
|
|
||||||
|
setBasePath(compiler) {
|
||||||
|
this.basePath = compiler.options.context;
|
||||||
|
}
|
||||||
|
|
||||||
|
// async enforceTarget(compiler) {
|
||||||
|
// const { options } = compiler;
|
||||||
|
// // set jsonp obj motuned obj
|
||||||
|
// options.output.globalObject = 'global';
|
||||||
|
// options.node = {
|
||||||
|
// ...(options.node || {}),
|
||||||
|
// global: false,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// // set target to web
|
||||||
|
// new JsonpTemplatePlugin(options.output).apply(compiler);
|
||||||
|
// new NodeSourcePlugin(options.node).apply(compiler);
|
||||||
|
// new LoaderTargetPlugin('web').apply(compiler);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// script full path
|
||||||
|
getFullScriptPath(script) {
|
||||||
|
const {
|
||||||
|
basePath,
|
||||||
|
options: { extensions },
|
||||||
|
} = this;
|
||||||
|
for (const ext of extensions) {
|
||||||
|
const fullPath = path.resolve(basePath, script + ext);
|
||||||
|
if (fsExtra.existsSync(fullPath)) {
|
||||||
|
return fullPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async clearOutPut(compilation) {
|
||||||
|
const { path } = compilation.options.output;
|
||||||
|
await fsExtra.remove(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = OakWeChatMpPlugin;
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
const {
|
||||||
|
buildSchema,
|
||||||
|
analyzeEntities,
|
||||||
|
} = require(`${process.cwd()}/node_modules/oak-domain/src/compiler/schemalBuilder`);
|
||||||
|
|
||||||
|
analyzeEntities(`${process.cwd()}/node_modules/oak-general-business/src/entities`);
|
||||||
|
analyzeEntities(`${process.cwd()}/src/entities`);
|
||||||
|
buildSchema(`${process.cwd()}/oak-app-domain`);
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
const webpack = require('webpack');
|
||||||
|
const chalk = require('chalk');
|
||||||
|
|
||||||
|
const webpackConfig = require('../config/webpack.config');
|
||||||
|
|
||||||
|
webpack(webpackConfig, (err, stats) => {
|
||||||
|
if (err) {
|
||||||
|
console.log(chalk.red(err.stack || err));
|
||||||
|
if (err.details) {
|
||||||
|
console.log(chalk.red(err.details));
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (stats) {
|
||||||
|
const info = stats.toJson();
|
||||||
|
if (stats.hasErrors()) {
|
||||||
|
info.errors.forEach(
|
||||||
|
ele => console.warn(ele)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (stats.hasWarnings()) {
|
||||||
|
info.warnings.forEach(
|
||||||
|
ele => console.warn(ele)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
import {
|
||||||
|
Success,
|
||||||
|
Error,
|
||||||
|
error,
|
||||||
|
primary,
|
||||||
|
success,
|
||||||
|
warn,
|
||||||
|
Warn,
|
||||||
|
} from './tip-style';
|
||||||
|
import spawn from 'cross-spawn';
|
||||||
|
|
||||||
|
export default async function build(env: string) {
|
||||||
|
Success(`${success(`build环境:${env}`)}`);
|
||||||
|
const result = spawn.sync(
|
||||||
|
process.execPath,
|
||||||
|
[require.resolve('../scripts/' + 'webpack.js')].concat([env]),
|
||||||
|
{
|
||||||
|
stdio: 'inherit',
|
||||||
|
shell: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// const result = spawn.sync('npm -v', [], { stdio: 'inherit', shell: true });
|
||||||
|
if (result.status === 0) {
|
||||||
|
Success(`${success(`执行完成`)}`);
|
||||||
|
} else {
|
||||||
|
Error(`${error(`执行失败`)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
export const CLI_VERSION = require('../package.json')['version']
|
||||||
|
export const CLI_NAME = require('../package.json')['name']
|
||||||
|
|
||||||
|
export const BASE_DIR = process.cwd()
|
||||||
|
|
||||||
|
export const USER_CONFIG_FILE_NAME = 'oak.config.json'
|
||||||
|
export const USER_CONFIG_FILE = BASE_DIR + '/' + USER_CONFIG_FILE_NAME
|
||||||
|
|
||||||
|
export const NODE_MODULES_DIR_NAME = 'node_modules'
|
||||||
|
|
||||||
|
export const CNPM_BASE_URL = '' //oak-cli
|
||||||
|
export const MINI_VERSION_URL = 'https://mp.weixin.qq.com/debug/getpublibpercentage'
|
||||||
|
|
@ -0,0 +1,209 @@
|
||||||
|
import {
|
||||||
|
copyFolder,
|
||||||
|
checkFileExistsAndCreate,
|
||||||
|
readFile,
|
||||||
|
checkFileExists,
|
||||||
|
} from './file-handle';
|
||||||
|
import { checkFileExistsAndCreateType } from './enum';
|
||||||
|
import {
|
||||||
|
CNPM_BASE_URL,
|
||||||
|
CLI_VERSION,
|
||||||
|
USER_CONFIG_FILE_NAME,
|
||||||
|
CLI_NAME,
|
||||||
|
MINI_VERSION_URL,
|
||||||
|
} from './config';
|
||||||
|
import {
|
||||||
|
packageJsonContent,
|
||||||
|
tsConfigJsonContent,
|
||||||
|
projectConfigContentWithWeChatMp,
|
||||||
|
oakConfigContentWithWeChatMp,
|
||||||
|
} from './template';
|
||||||
|
import { PromptInput, OakInput } from './interface';
|
||||||
|
import { join } from 'path';
|
||||||
|
import inquirer from 'inquirer';
|
||||||
|
import axios from 'axios';
|
||||||
|
import {
|
||||||
|
Success,
|
||||||
|
Error,
|
||||||
|
error,
|
||||||
|
primary,
|
||||||
|
success,
|
||||||
|
warn,
|
||||||
|
Warn,
|
||||||
|
} from './tip-style';
|
||||||
|
import shell from 'shelljs';
|
||||||
|
|
||||||
|
const prompt = [
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
name: 'version',
|
||||||
|
message: 'version',
|
||||||
|
default: '1.0.0',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
name: 'description',
|
||||||
|
message: 'description',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name 检查项目名是否已存在
|
||||||
|
* @param dirName
|
||||||
|
*/
|
||||||
|
function checkProjectName(dirName: string) {
|
||||||
|
// 项目根路径
|
||||||
|
const rootPath = process.cwd() + '/' + dirName;
|
||||||
|
const isExists = checkFileExists(rootPath);
|
||||||
|
if (isExists) {
|
||||||
|
console.error(
|
||||||
|
error(
|
||||||
|
`Cannot create a project named ${success(
|
||||||
|
`"${dirName}"`
|
||||||
|
)} because a path with the same name exists.\n`
|
||||||
|
) + error('Please choose a different project name.')
|
||||||
|
);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name 获取oak-cli最新版本号
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async function getOakCliVersion() {
|
||||||
|
const res = await axios.get(CNPM_BASE_URL);
|
||||||
|
return res.data['dist-tags']['latest'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name 获取微信小程序稳定基础版本库
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async function getMiniVersion() {
|
||||||
|
const res = await axios.get(MINI_VERSION_URL);
|
||||||
|
const versions: Array<any> = JSON.parse(res.data['json_data'])['total'];
|
||||||
|
const versionsSort = versions.sort((a: any, b: any) => {
|
||||||
|
return b['percentage'] - a['percentage'];
|
||||||
|
});
|
||||||
|
return versionsSort[0]['sdkVer'];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function create(dirName: string, env: string) {
|
||||||
|
const nameOption = {
|
||||||
|
type: 'input',
|
||||||
|
name: 'name',
|
||||||
|
message: `name`,
|
||||||
|
default: dirName,
|
||||||
|
};
|
||||||
|
prompt.unshift(nameOption);
|
||||||
|
|
||||||
|
const isDev = env === 'dev' || env === 'development';
|
||||||
|
|
||||||
|
const { name, version, description }: PromptInput = await inquirer.prompt(
|
||||||
|
prompt
|
||||||
|
);
|
||||||
|
// 获取微信小程序稳定基础版本库
|
||||||
|
const miniVersion = await getMiniVersion();
|
||||||
|
// 获取package.json内容
|
||||||
|
const packageJson = packageJsonContent({
|
||||||
|
name,
|
||||||
|
version,
|
||||||
|
description,
|
||||||
|
cliversion: CLI_VERSION,
|
||||||
|
cliname: CLI_NAME,
|
||||||
|
isDev,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取tsconfig.json内容
|
||||||
|
const tsconfigJson = tsConfigJsonContent();
|
||||||
|
|
||||||
|
// 获取小程序项目project.config.json内容
|
||||||
|
const projectConfigWithWeChatMp = projectConfigContentWithWeChatMp(
|
||||||
|
USER_CONFIG_FILE_NAME,
|
||||||
|
'wechatMp',
|
||||||
|
miniVersion
|
||||||
|
);
|
||||||
|
// 获取小程序项目oak.config.json内容
|
||||||
|
const oakConfigWithWeChatMp = oakConfigContentWithWeChatMp();
|
||||||
|
// 项目根路径
|
||||||
|
const rootPath = process.cwd() + '/' + dirName;
|
||||||
|
// package.json路径
|
||||||
|
const packageJsonPath = `${rootPath}/package.json`;
|
||||||
|
// tsconfig.json路径
|
||||||
|
const tsconfigJsonPath = `${rootPath}/tsconfig.json`;
|
||||||
|
// web项目根路径
|
||||||
|
const webRootPath = `${rootPath}/web`;
|
||||||
|
// 小程序项目根路径
|
||||||
|
const weChatMpRootPath = `${rootPath}/wechatMp`;
|
||||||
|
|
||||||
|
// 小程序项目project.config.json路径
|
||||||
|
const projectConfigPathWithWeChatMp = `${weChatMpRootPath}/src/project.config.json`;
|
||||||
|
// 小程序项目project.config.json路径
|
||||||
|
const oakConfigPathWithWeChatMp = `${weChatMpRootPath}/src/${USER_CONFIG_FILE_NAME}`;
|
||||||
|
// 被复制的文件夹路径
|
||||||
|
const currentPath = join(__dirname, '..') + '/template';
|
||||||
|
//检查项目名是否存在
|
||||||
|
checkProjectName(dirName);
|
||||||
|
try {
|
||||||
|
// 创建根目录
|
||||||
|
checkFileExistsAndCreate(rootPath);
|
||||||
|
// 创建package.json
|
||||||
|
checkFileExistsAndCreate(
|
||||||
|
packageJsonPath,
|
||||||
|
packageJson,
|
||||||
|
checkFileExistsAndCreateType.FILE
|
||||||
|
);
|
||||||
|
// 创建tsconfig.json
|
||||||
|
checkFileExistsAndCreate(
|
||||||
|
tsconfigJsonPath,
|
||||||
|
tsconfigJson,
|
||||||
|
checkFileExistsAndCreateType.FILE
|
||||||
|
);
|
||||||
|
// 复制项目文件
|
||||||
|
copyFolder(currentPath, rootPath);
|
||||||
|
// 创建小程序项目project.config.json
|
||||||
|
checkFileExistsAndCreate(
|
||||||
|
projectConfigPathWithWeChatMp,
|
||||||
|
projectConfigWithWeChatMp,
|
||||||
|
checkFileExistsAndCreateType.FILE
|
||||||
|
);
|
||||||
|
// 创建小程序项目oak.config.json
|
||||||
|
checkFileExistsAndCreate(
|
||||||
|
oakConfigPathWithWeChatMp,
|
||||||
|
oakConfigWithWeChatMp,
|
||||||
|
checkFileExistsAndCreateType.FILE
|
||||||
|
);
|
||||||
|
if (!shell.which('npm')) {
|
||||||
|
Warn(warn('Sorry, this script requires npm! Please install npm!'));
|
||||||
|
shell.exit(1);
|
||||||
|
}
|
||||||
|
Success(`${success(`Waiting...`)}`);
|
||||||
|
Success(`${success(`Dependencies are now being installed`)}`);
|
||||||
|
shell.cd(dirName).exec('npm install');
|
||||||
|
|
||||||
|
// checkFileExistsAndCreate(weChatMpRootPath + '/src/styles');
|
||||||
|
// //const data = readFile(
|
||||||
|
// // `${rootPath}/node_modules/oak-frontend-boilerplate/src/platforms/wechatMp/styles/base.less`
|
||||||
|
// //);
|
||||||
|
// const data = readFile(
|
||||||
|
// `${rootPath}/node_modules/oak-general-business/src/platforms/wechatMp/styles/base.less`
|
||||||
|
// );
|
||||||
|
// checkFileExistsAndCreate(
|
||||||
|
// weChatMpRootPath + '/src/styles/base.less',
|
||||||
|
// data,
|
||||||
|
// checkFileExistsAndCreateType.FILE
|
||||||
|
// );
|
||||||
|
|
||||||
|
Success(
|
||||||
|
`${success(
|
||||||
|
`Successfully created project ${primary(
|
||||||
|
name
|
||||||
|
)}, directory name is ${primary(dirName)}`
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
Error(error('create error'));
|
||||||
|
Error(error(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
/**
|
||||||
|
* @name 检查文件时用到的枚举
|
||||||
|
* @export
|
||||||
|
* @enum {number}
|
||||||
|
*/
|
||||||
|
export enum checkFileExistsAndCreateType {
|
||||||
|
DIRECTORY,
|
||||||
|
FILE
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,197 @@
|
||||||
|
import { readdirSync, statSync, writeFileSync, PathLike, existsSync, unlinkSync, mkdirSync, rmdirSync, createReadStream, accessSync, createWriteStream, constants, readFileSync } from 'fs'
|
||||||
|
import { join } from 'path'
|
||||||
|
import { checkFileExistsAndCreateType } from './enum'
|
||||||
|
import { Error, error, Warn, warn } from './tip-style'
|
||||||
|
const pathList: Set<string> = new Set()
|
||||||
|
/**
|
||||||
|
* @name 读取目录下所有文件
|
||||||
|
* @export
|
||||||
|
* @param {string} entry 目录名称
|
||||||
|
*/
|
||||||
|
export function readDirPath(entry: string): Set<string> {
|
||||||
|
const dirInfo = readdirSync(entry);
|
||||||
|
for (let item of dirInfo) {
|
||||||
|
const location = join(entry, item);
|
||||||
|
const info = statSync(location);
|
||||||
|
if (info.isDirectory()) {
|
||||||
|
readDirPath(location);
|
||||||
|
} else {
|
||||||
|
pathList.add(location)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pathList
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name 读取指定目录的文件(不进行深度遍历,只获取根目录)
|
||||||
|
* @export
|
||||||
|
* @param {*} entry
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function readDirGetFile(entry: string) {
|
||||||
|
const dirInfo = readdirSync(entry);
|
||||||
|
return dirInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name 解析json文件(数组)
|
||||||
|
* @export
|
||||||
|
* @param {Array<string>} arr
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function parseJsonFiles(arr: Set<string>) {
|
||||||
|
const result = []
|
||||||
|
for (let item of arr) {
|
||||||
|
const data = parseJsonFile(item);
|
||||||
|
result.push(data)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name 解析单个文件json
|
||||||
|
* @export
|
||||||
|
* @param {PathLike} file
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function parseJsonFile(file: string) {
|
||||||
|
try {
|
||||||
|
const data = readFileSync(file, 'utf8');
|
||||||
|
return JSON.parse(data)
|
||||||
|
} catch (error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name 删除文件夹
|
||||||
|
* @export
|
||||||
|
* @param {string} entry
|
||||||
|
*/
|
||||||
|
export function deleteFolderRecursive(entry: string) {
|
||||||
|
let files = [];
|
||||||
|
// 判断给定的路径是否存在
|
||||||
|
if (existsSync(entry)) {
|
||||||
|
// 返回文件和子目录的数组
|
||||||
|
files = readdirSync(entry);
|
||||||
|
for (let file of files) {
|
||||||
|
const curPath = join(entry, file);
|
||||||
|
// fs.statSync同步读取文件夹文件,如果是文件夹,在重复触发函数
|
||||||
|
if (statSync(curPath).isDirectory()) { // recurse
|
||||||
|
deleteFolderRecursive(curPath);
|
||||||
|
// 是文件delete file
|
||||||
|
} else {
|
||||||
|
unlinkSync(curPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 清除文件夹
|
||||||
|
rmdirSync(entry);
|
||||||
|
} else {
|
||||||
|
// console.log("文件夹不存在");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export function writeFile(path: string | PathLike, data: any) {
|
||||||
|
try {
|
||||||
|
writeFileSync(path, data)
|
||||||
|
} catch (err) {
|
||||||
|
Error(error(err))
|
||||||
|
Error(error('文件写入失败'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function readFile(
|
||||||
|
path: string | PathLike,
|
||||||
|
options?: { encoding?: null | undefined; flag?: string | undefined } | null
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const data = readFileSync(path, options);
|
||||||
|
return data;
|
||||||
|
} catch (err) {
|
||||||
|
Error(error(err));
|
||||||
|
Error(error('文件读取失败'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name 拷贝文件夹
|
||||||
|
* @export
|
||||||
|
* @param {PathLike} currentDir
|
||||||
|
* @param {PathLike} targetDir
|
||||||
|
*/
|
||||||
|
export function copyFolder(currentDir: PathLike, targetDir: PathLike) {
|
||||||
|
|
||||||
|
function handleFolder(currentDir: PathLike, targetDir: PathLike) {
|
||||||
|
const files = readdirSync(currentDir, {
|
||||||
|
withFileTypes: true
|
||||||
|
})
|
||||||
|
for (let file of files) {
|
||||||
|
// 拼接文件绝对路径
|
||||||
|
const copyCurrentFileInfo = currentDir + '/' + file.name
|
||||||
|
const copyTargetFileInfo = targetDir + '/' + file.name
|
||||||
|
// 判断文件是否存在
|
||||||
|
const readCurrentFile = existsSync(copyCurrentFileInfo)
|
||||||
|
const readTargetFile = existsSync(copyTargetFileInfo)
|
||||||
|
if (readCurrentFile && !readTargetFile) {
|
||||||
|
// 判断是否为文件,如果为文件则复制,文件夹则递归
|
||||||
|
if (file.isFile()) {
|
||||||
|
const readStream = createReadStream(copyCurrentFileInfo)
|
||||||
|
const writeStream = createWriteStream(copyTargetFileInfo)
|
||||||
|
readStream.pipe(writeStream)
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
accessSync(join(copyTargetFileInfo, '..'), constants.W_OK)
|
||||||
|
copyFolder(copyCurrentFileInfo, copyTargetFileInfo)
|
||||||
|
} catch (error) {
|
||||||
|
Warn('权限不足' + error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Error(error('操作失败,target文件夹已存在或current文件夹不存在'))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existsSync(currentDir)) {
|
||||||
|
if (!existsSync(targetDir)) {
|
||||||
|
mkdirSync(targetDir)
|
||||||
|
}
|
||||||
|
handleFolder(currentDir, targetDir)
|
||||||
|
} else {
|
||||||
|
Warn(warn('需要copy的文件夹不存在:' + currentDir))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name 检测文件/文件夹是否存在
|
||||||
|
* @export
|
||||||
|
* @param {(PathLike | string)} path
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function checkFileExists(path: PathLike | string) {
|
||||||
|
return existsSync(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name 检测文件/文件夹是否存在,不存在则创建
|
||||||
|
* @export
|
||||||
|
* @param {(PathLike | string)} path
|
||||||
|
* @param {*} [data]
|
||||||
|
* @param {checkFileExistsAndCreateType} [type=checkFileExistsAndCreateType.DIRECTORY]
|
||||||
|
*/
|
||||||
|
export function checkFileExistsAndCreate(path: PathLike | string, data?: any, type: checkFileExistsAndCreateType = checkFileExistsAndCreateType.DIRECTORY): void {
|
||||||
|
if (!checkFileExists(path)) {
|
||||||
|
switch (type) {
|
||||||
|
case checkFileExistsAndCreateType.DIRECTORY:
|
||||||
|
mkdirSync(path)
|
||||||
|
break;
|
||||||
|
case checkFileExistsAndCreateType.FILE:
|
||||||
|
writeFile(path, data)
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
mkdirSync(path)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
import program from 'commander';
|
||||||
|
import create from './create';
|
||||||
|
import build from './build';
|
||||||
|
import make from './make';
|
||||||
|
import { CLI_VERSION, CLI_NAME } from './config';
|
||||||
|
import { error, warn } from './tip-style';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name 未知参数错误提示
|
||||||
|
* @param {string} methodName
|
||||||
|
* @param {Function} log
|
||||||
|
*/
|
||||||
|
function enhanceErrorMessages(methodName: string, log: Function) {
|
||||||
|
program.Command.prototype[methodName] = function (...args: any) {
|
||||||
|
if (methodName === 'unknownOption' && this._allowUnknownOption) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.outputHelp();
|
||||||
|
console.log(` ` + error(log(...args)));
|
||||||
|
console.log();
|
||||||
|
process.exit(1);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentNodeVersion = process.versions.node;
|
||||||
|
const semver = currentNodeVersion.split('.');
|
||||||
|
const major = semver[0];
|
||||||
|
const minNodeVersion = 14;
|
||||||
|
|
||||||
|
if (Number(major) < minNodeVersion) {
|
||||||
|
console.error(
|
||||||
|
'You are running Node ' +
|
||||||
|
currentNodeVersion +
|
||||||
|
'.\n' +
|
||||||
|
'Create React App requires Node ' +
|
||||||
|
minNodeVersion +
|
||||||
|
' or higher. \n' +
|
||||||
|
'Please update your version of Node.'
|
||||||
|
);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
program.version(CLI_VERSION, '-v, --version').usage('<command> [options]');
|
||||||
|
|
||||||
|
program
|
||||||
|
.command('make')
|
||||||
|
.description('build oak app domain of make on demand')
|
||||||
|
.action(make);
|
||||||
|
program
|
||||||
|
.command('start <env>')
|
||||||
|
.usage('<env>')
|
||||||
|
.description('build we chat mp of start on demand')
|
||||||
|
.action(build);
|
||||||
|
program
|
||||||
|
.command('build <env>')
|
||||||
|
.usage('<env>')
|
||||||
|
.description('build we chat mp of build on demand')
|
||||||
|
.action(build);
|
||||||
|
program
|
||||||
|
.command('create <name> [env]')
|
||||||
|
.usage('<name>')
|
||||||
|
// .option('-e, --env <env>', 'A env')
|
||||||
|
.description(`create a new project powered by ${CLI_NAME}`)
|
||||||
|
.action(create);
|
||||||
|
// output help information on unknown commands
|
||||||
|
program.arguments('<command>').action((cmd) => {
|
||||||
|
program.outputHelp();
|
||||||
|
console.log();
|
||||||
|
console.log(` ` + `${error(`Unknown command ${warn(cmd)}`)}`);
|
||||||
|
console.log();
|
||||||
|
});
|
||||||
|
|
||||||
|
enhanceErrorMessages('missingArgument', (argName: string) => {
|
||||||
|
console.log();
|
||||||
|
return `${error(`Missing required argument ${warn(argName)}.`)}`;
|
||||||
|
});
|
||||||
|
program.parse(process.argv);
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name 生成package.json需要输入的参数
|
||||||
|
* @export
|
||||||
|
* @interface PackageJsonInput
|
||||||
|
*/
|
||||||
|
export interface PackageJsonInput {
|
||||||
|
name: string;
|
||||||
|
version?: string;
|
||||||
|
description?: string;
|
||||||
|
cliversion: string;
|
||||||
|
cliname: string;
|
||||||
|
isDev?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Prompt需要输入的参数
|
||||||
|
* @export
|
||||||
|
* @interface PromptInput
|
||||||
|
*/
|
||||||
|
export interface PromptInput {
|
||||||
|
name: string,
|
||||||
|
version: string,
|
||||||
|
description: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name project.config.json
|
||||||
|
* @export
|
||||||
|
* @interface ProjectConfigInterface
|
||||||
|
*/
|
||||||
|
export interface ProjectConfigInterface {
|
||||||
|
packOptions: PackOptions
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @name project.config.json PackOptions
|
||||||
|
* @export
|
||||||
|
* @interface PackOptions
|
||||||
|
*/
|
||||||
|
export interface PackOptions {
|
||||||
|
ignore: Array<PackOptionsIgnore>
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @name project.config.json PackOptions PackOptionsIgnore
|
||||||
|
* @export
|
||||||
|
* @interface PackOptionsIgnore
|
||||||
|
*/
|
||||||
|
export interface PackOptionsIgnore {
|
||||||
|
type: string,
|
||||||
|
value: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name oak-cli需要输入的参数
|
||||||
|
* @export
|
||||||
|
* @interface OakInput
|
||||||
|
*/
|
||||||
|
export interface OakInput {
|
||||||
|
mode: string,
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
import {
|
||||||
|
Success,
|
||||||
|
Error,
|
||||||
|
error,
|
||||||
|
primary,
|
||||||
|
success,
|
||||||
|
warn,
|
||||||
|
Warn,
|
||||||
|
} from './tip-style';
|
||||||
|
import spawn from 'cross-spawn';
|
||||||
|
|
||||||
|
export default async function make() {
|
||||||
|
Success(`${success(`build oak app domain`)}`);
|
||||||
|
// ts-node scripts/build-app-domain & npm link ./app-domain
|
||||||
|
const result = spawn.sync(
|
||||||
|
'ts-node',
|
||||||
|
[require.resolve('../scripts/' + 'build-app-domain.js')],
|
||||||
|
{
|
||||||
|
stdio: 'inherit',
|
||||||
|
shell: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// const result2 = spawn.sync('npm -v', [], { stdio: 'inherit', shell: true });
|
||||||
|
|
||||||
|
if (result.status === 0) {
|
||||||
|
Success(`${success(`build 执行完成`)}`);
|
||||||
|
} else {
|
||||||
|
Error(`${error(`build 执行失败`)}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Success(`${success(`npm link oak app domain`)}`);
|
||||||
|
|
||||||
|
const isMac = process.platform === 'darwin';
|
||||||
|
const result2 = spawn.sync(
|
||||||
|
`${isMac ? 'sudo' : ''} npm`,
|
||||||
|
[`link ${process.cwd()}/oak-app-domain`],
|
||||||
|
{
|
||||||
|
stdio: 'inherit',
|
||||||
|
shell: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result2.status === 0) {
|
||||||
|
Success(`${success(`link 执行完成`)}`);
|
||||||
|
} else {
|
||||||
|
Error(`${error(`link 执行失败`)}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,213 @@
|
||||||
|
import { PackageJsonInput } from './interface'
|
||||||
|
export function packageJsonContent({
|
||||||
|
name,
|
||||||
|
version,
|
||||||
|
description,
|
||||||
|
cliversion,
|
||||||
|
cliname,
|
||||||
|
isDev,
|
||||||
|
}: PackageJsonInput) {
|
||||||
|
let oakPackageStr;
|
||||||
|
if (isDev) {
|
||||||
|
oakPackageStr = `"${cliname}": "file:../${cliname}",
|
||||||
|
"oak-domain": "file:../oak-domain",
|
||||||
|
"oak-frontend-base": "file:../oak-frontend-base",
|
||||||
|
"oak-general-business": "file:../oak-general-business",
|
||||||
|
"oak-memory-tree-store": "file:../oak-memory-tree-store",`;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
oakPackageStr = `"${cliname}": "^${cliversion}",
|
||||||
|
"oak-domain": "^1.0.0",
|
||||||
|
"oak-frontend-base": "^1.0.0",
|
||||||
|
"oak-general-business": "^1.0.0",
|
||||||
|
"oak-memory-tree-store": "^1.0.0",`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `{
|
||||||
|
"name": "${name}",
|
||||||
|
"version": "${version}",
|
||||||
|
"description": "${description}",
|
||||||
|
"scripts": {
|
||||||
|
"make:domain": "${cliname} make",
|
||||||
|
"start:mp": "${cliname} start development",
|
||||||
|
"build:mp": "${cliname} build production"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "",
|
||||||
|
"dependencies": {
|
||||||
|
"@reduxjs/toolkit": "^1.7.2",
|
||||||
|
"crypto-browserify": "^3.12.0",
|
||||||
|
"lodash": "^4.17.21"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/cli": "^7.12.13",
|
||||||
|
"@babel/core": "^7.12.13",
|
||||||
|
"@babel/plugin-proposal-class-properties": "^7.12.13",
|
||||||
|
"@babel/preset-env": "^7.12.13",
|
||||||
|
"@babel/preset-typescript": "^7.12.13",
|
||||||
|
"@types/assert": "^1.5.6",
|
||||||
|
"@types/fs-extra": "^9.0.13",
|
||||||
|
"@types/lodash": "^4.14.179",
|
||||||
|
"@types/mocha": "^8.2.0",
|
||||||
|
"@types/node": "^14.14.25",
|
||||||
|
"@types/react": "^17.0.2",
|
||||||
|
"@types/shelljs": "^0.8.11",
|
||||||
|
"@types/uuid": "^8.3.0",
|
||||||
|
"@types/wechat-miniprogram": "^3.4.0",
|
||||||
|
"assert": "^2.0.0",
|
||||||
|
"babel-loader": "^8.2.3",
|
||||||
|
"chalk": "^4.1.2",
|
||||||
|
"clean-webpack-plugin": "^4.0.0",
|
||||||
|
"copy-webpack-plugin": "^10.2.4",
|
||||||
|
"cross-env": "^7.0.2",
|
||||||
|
"css-loader": "^6.6.0",
|
||||||
|
"dotenv-webpack": "^7.1.0",
|
||||||
|
"ensure-posix-path": "^1.1.1",
|
||||||
|
"file-loader": "^6.2.0",
|
||||||
|
"fs-extra": "^10.0.0",
|
||||||
|
"globby": "^11.1.0",
|
||||||
|
"less-loader": "^10.2.0",
|
||||||
|
"mini-css-extract-plugin": "^2.5.3",
|
||||||
|
"miniprogram-api-typings": "^3.4.5",
|
||||||
|
"mocha": "^8.2.1",
|
||||||
|
${oakPackageStr}
|
||||||
|
"postcss-less": "^6.0.0",
|
||||||
|
"progress": "^2.0.3",
|
||||||
|
"progress-bar-webpack-plugin": "^2.1.0",
|
||||||
|
"required-path": "^1.0.1",
|
||||||
|
"shelljs": "^0.8.5",
|
||||||
|
"style-loader": "^3.3.1",
|
||||||
|
"stylelint-config-standard": "^25.0.0",
|
||||||
|
"stylelint-webpack-plugin": "^3.1.1",
|
||||||
|
"ts-loader": "^9.2.6",
|
||||||
|
"ts-node": "^9.1.1",
|
||||||
|
"typescript": "^4.5.2",
|
||||||
|
"ui-extract-webpack-plugin": "^1.0.0",
|
||||||
|
"webpack": "^5.69.1",
|
||||||
|
"webpack-dashboard": "^3.3.7"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function tsConfigJsonContent() {
|
||||||
|
return `{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "CommonJS",
|
||||||
|
"target": "esnext",
|
||||||
|
"allowJs": false,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"strict": true,
|
||||||
|
"lib": [
|
||||||
|
"ES2020"
|
||||||
|
],
|
||||||
|
"typeRoots": [
|
||||||
|
"./src/typings"
|
||||||
|
],
|
||||||
|
"types": [
|
||||||
|
"node",
|
||||||
|
"miniprogram-api-typings"
|
||||||
|
],
|
||||||
|
"resolveJsonModule": true /* Disallow inconsistently-cased references to the same file. */
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"./**/*.ts",
|
||||||
|
"scripts/webpack.js"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
]
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function projectConfigContentWithWeChatMp(
|
||||||
|
oakConfigName: string,
|
||||||
|
projectname: string,
|
||||||
|
miniVersion: string
|
||||||
|
) {
|
||||||
|
return `{
|
||||||
|
"description": "项目配置文件",
|
||||||
|
"packOptions": {
|
||||||
|
"ignore": [{
|
||||||
|
"type": "file",
|
||||||
|
"value": "${oakConfigName}"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"setting": {
|
||||||
|
"urlCheck": true,
|
||||||
|
"es6": true,
|
||||||
|
"enhance": true,
|
||||||
|
"postcss": true,
|
||||||
|
"preloadBackgroundData": false,
|
||||||
|
"minified": true,
|
||||||
|
"newFeature": false,
|
||||||
|
"coverView": true,
|
||||||
|
"nodeModules": true,
|
||||||
|
"autoAudits": false,
|
||||||
|
"showShadowRootInWxmlPanel": true,
|
||||||
|
"scopeDataCheck": false,
|
||||||
|
"uglifyFileName": false,
|
||||||
|
"checkInvalidKey": true,
|
||||||
|
"checkSiteMap": true,
|
||||||
|
"uploadWithSourceMap": true,
|
||||||
|
"compileHotReLoad": false,
|
||||||
|
"babelSetting": {
|
||||||
|
"ignore": [],
|
||||||
|
"disablePlugins": [],
|
||||||
|
"outputPath": ""
|
||||||
|
},
|
||||||
|
"useIsolateContext": true,
|
||||||
|
"useCompilerModule": false,
|
||||||
|
"userConfirmedUseCompilerModuleSwitch": false
|
||||||
|
},
|
||||||
|
"compileType": "miniprogram",
|
||||||
|
"libVersion": "${miniVersion}",
|
||||||
|
"appid": "",
|
||||||
|
"projectname": "${projectname}",
|
||||||
|
"debugOptions": {
|
||||||
|
"hidedInDevtools": []
|
||||||
|
},
|
||||||
|
"scripts": "",
|
||||||
|
"isGameTourist": false,
|
||||||
|
"simulatorType": "wechat",
|
||||||
|
"simulatorPluginLibVersion": {},
|
||||||
|
"condition": {
|
||||||
|
"search": {
|
||||||
|
"current": -1,
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
|
"conversation": {
|
||||||
|
"current": -1,
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
|
"game": {
|
||||||
|
"current": -1,
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
|
"plugin": {
|
||||||
|
"current": -1,
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
|
"gamePlugin": {
|
||||||
|
"current": -1,
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
|
"miniprogram": {
|
||||||
|
"current": -1,
|
||||||
|
"list": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function oakConfigContentWithWeChatMp() {
|
||||||
|
return `{
|
||||||
|
"theme": {
|
||||||
|
"@primary-color": "#2d8cf0"
|
||||||
|
}
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
import chalk from 'chalk'
|
||||||
|
import consola from 'consola'
|
||||||
|
|
||||||
|
// tip type
|
||||||
|
export const Success = (content: any) => consola.success(content)
|
||||||
|
export const Error = (content: any) => consola.error(content)
|
||||||
|
export const Start = (content: any) => consola.start(content)
|
||||||
|
export const Warn = (content: any) => consola.warn(content)
|
||||||
|
// tip style
|
||||||
|
export const success = (content: any) => chalk.greenBright(content)
|
||||||
|
export const error = (content: any) => chalk.redBright(content)
|
||||||
|
export const primary = (content: any) => chalk.blueBright(content)
|
||||||
|
export const warn = (content: any) => chalk.yellowBright(content)
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name 从一组路径里查找到所有json文件
|
||||||
|
* @export
|
||||||
|
* @param {Array<string>} pathArr
|
||||||
|
* @returns {Set<string>}
|
||||||
|
*/
|
||||||
|
export function findJson(pathArr: Set<string>): Set<string> {
|
||||||
|
const result: Set<string> = new Set()
|
||||||
|
for (let item of pathArr) {
|
||||||
|
const endIndex = item.length
|
||||||
|
const str = item.substring(endIndex - 5, endIndex)
|
||||||
|
if (str === '.json') {
|
||||||
|
result.add(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name 已知前后文取中间文本
|
||||||
|
* @export
|
||||||
|
* @param {string} str
|
||||||
|
* @param {string} start
|
||||||
|
* @param {string} end
|
||||||
|
* @returns {(string | null)}
|
||||||
|
*/
|
||||||
|
export function getStr(str: string, start: string, end: string): string | null {
|
||||||
|
const reg = new RegExp(`${start}(.*?)${end}`)
|
||||||
|
let res = str.match(reg)
|
||||||
|
return res ? res[1] : null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name 差集
|
||||||
|
* @export
|
||||||
|
* @template T
|
||||||
|
* @param {Set<T>} current
|
||||||
|
* @param {Set<T>} target
|
||||||
|
* @returns {Set<T>}
|
||||||
|
*/
|
||||||
|
export function difference<T>(current: Set<T>, target: Set<T>): Set<T> {
|
||||||
|
return new Set(
|
||||||
|
[...target].filter(x => !current.has(x))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name 获取交集
|
||||||
|
* @export
|
||||||
|
* @template T
|
||||||
|
* @param {Set<T>} current
|
||||||
|
* @param {Set<T>} target
|
||||||
|
* @returns {Set<T>}
|
||||||
|
*/
|
||||||
|
export function intersect<T>(current: Set<T>, target: Set<T>): Set<T> {
|
||||||
|
return new Set([...target].filter(x => current.has(x)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name 获取并集
|
||||||
|
* @export
|
||||||
|
* @template T
|
||||||
|
* @param {Set<T>} current
|
||||||
|
* @param {Set<T>} target
|
||||||
|
* @returns {Set<T>}
|
||||||
|
*/
|
||||||
|
export function union<T>(current: Set<T>, target: Set<T>): Set<T> {
|
||||||
|
return new Set([...current, ...target])
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name 格式化json
|
||||||
|
* @export
|
||||||
|
* @template T
|
||||||
|
* @param {T} data
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
export function formatJsonByFile<T extends Object>(data: T): string {
|
||||||
|
return JSON.stringify(data, null, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name 数组对象去重
|
||||||
|
* @export
|
||||||
|
* @param {Array<any>} arr 需要去重的数组或set
|
||||||
|
* @param {*} [type] 需要根据哪个字段去重
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function deWeight(arr: Array<any> | Set<any>, type: any) {
|
||||||
|
let map = new Map();
|
||||||
|
for (let item of arr) {
|
||||||
|
if (!map.has(item[type])) {
|
||||||
|
map.set(item[type], item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new Set([...map.values()]);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
# Snowpack dependency directory (https://snowpack.dev/)
|
||||||
|
web_modules/
|
||||||
|
# TypeScript cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
# Microbundle cache
|
||||||
|
.rpt2_cache/
|
||||||
|
.rts2_cache_cjs/
|
||||||
|
.rts2_cache_es/
|
||||||
|
.rts2_cache_umd/
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env
|
||||||
|
.env.test
|
||||||
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
|
.cache
|
||||||
|
.parcel-cache
|
||||||
|
# Next.js build output
|
||||||
|
.next
|
||||||
|
out
|
||||||
|
# Nuxt.js build / generate output
|
||||||
|
.nuxt
|
||||||
|
dist
|
||||||
|
# Gatsby files
|
||||||
|
.cache/
|
||||||
|
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||||
|
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||||
|
# public
|
||||||
|
# vuepress build output
|
||||||
|
.vuepress/dist
|
||||||
|
# Serverless directories
|
||||||
|
.serverless/
|
||||||
|
# FuseBox cache
|
||||||
|
.fusebox/
|
||||||
|
# DynamoDB Local files
|
||||||
|
.dynamodb/
|
||||||
|
# TernJS port file
|
||||||
|
.tern-port
|
||||||
|
# Stores VSCode versions used for testing VSCode extensions
|
||||||
|
.vscode-test
|
||||||
|
# yarn v2
|
||||||
|
.yarn/cache
|
||||||
|
.yarn/unplugged
|
||||||
|
.yarn/build-state.yml
|
||||||
|
.yarn/install-state.gz
|
||||||
|
.pnp.*
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
customSyntax: 'postcss-less',
|
||||||
|
extends: 'stylelint-config-standard',
|
||||||
|
rules: {
|
||||||
|
'at-rule-no-vendor-prefix': true,
|
||||||
|
'media-feature-name-no-vendor-prefix': true,
|
||||||
|
'property-no-vendor-prefix': true,
|
||||||
|
'selector-max-compound-selectors': 10,
|
||||||
|
'selector-no-vendor-prefix': true,
|
||||||
|
'value-no-vendor-prefix': true,
|
||||||
|
'unit-no-unknown': [true, { ignoreUnits: ['rpx', 'px'] }],
|
||||||
|
'no-descending-specificity': null,
|
||||||
|
'at-rule-no-unknown': null,
|
||||||
|
'declaration-block-no-duplicate-properties': null,
|
||||||
|
'no-duplicate-selectors': null,
|
||||||
|
'selector-class-pattern': null,
|
||||||
|
'font-family-no-missing-generic-family-keyword': null,
|
||||||
|
'function-no-unknown': [true, { ignoreFunctions: ['alpha', 'constant', 'fadeout'] }],
|
||||||
|
'declaration-block-no-shorthand-property-overrides': null,
|
||||||
|
'no-empty-source': null,
|
||||||
|
'selector-type-no-unknown': null
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { test } from './sample';
|
||||||
|
|
||||||
|
const aspectDict = {
|
||||||
|
test
|
||||||
|
};
|
||||||
|
|
||||||
|
type AspectDict = typeof aspectDict;
|
||||||
|
|
||||||
|
export {
|
||||||
|
aspectDict,
|
||||||
|
AspectDict,
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { RuntimeContext } from "oak-general-business";
|
||||||
|
import { EntityDict } from '../../app-domain';
|
||||||
|
|
||||||
|
export async function test(params: string, context: RuntimeContext<EntityDict>) {
|
||||||
|
return 'hello world';
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { String, Int, Datetime, Image, Boolean, Text } from 'oak-domain/lib/types/DataType';
|
||||||
|
import { Schema as Area } from 'oak-general-business/lib/entities/Area';
|
||||||
|
import { Schema as User } from 'oak-general-business/lib/entities/User';
|
||||||
|
import { Schema as ExtraFile } from 'oak-general-business/lib/entities/ExtraFile';
|
||||||
|
import { EntityShape } from 'oak-domain/lib/types/Entity';
|
||||||
|
|
||||||
|
export interface Schema extends EntityShape {
|
||||||
|
district: String<16>;
|
||||||
|
area: Area;
|
||||||
|
owner: User;
|
||||||
|
dd: Array<ExtraFile>;
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { EntityDict } from '../../app-domain';
|
||||||
|
import { Feature } from 'oak-frontend-base';
|
||||||
|
import { AspectDict } from '../aspects';
|
||||||
|
import { Cache } from 'oak-frontend-base';
|
||||||
|
|
||||||
|
type DoSthAcion = {
|
||||||
|
type: 'doSth',
|
||||||
|
payload: {
|
||||||
|
args: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Sample extends Feature<EntityDict, AspectDict> {
|
||||||
|
get(params: any) {
|
||||||
|
throw new Error('Method not implemented.');
|
||||||
|
}
|
||||||
|
action(action: DoSthAcion) {
|
||||||
|
throw new Error('Method not implemented.');
|
||||||
|
}
|
||||||
|
cache: Cache<EntityDict, AspectDict>;
|
||||||
|
|
||||||
|
constructor(cache: Cache<EntityDict, AspectDict>) {
|
||||||
|
super();
|
||||||
|
this.cache = cache;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { EntityDict } from 'oak-app-domain';
|
||||||
|
import { BasicFeatures } from 'oak-frontend-base';
|
||||||
|
import * as Sample from './Sample';
|
||||||
|
import { AspectDict } from '../aspects';
|
||||||
|
|
||||||
|
export function initialize(features: BasicFeatures<EntityDict, AspectDict>) {
|
||||||
|
const { cache } = features;
|
||||||
|
|
||||||
|
const sample = new Sample.Sample(cache);
|
||||||
|
|
||||||
|
return {
|
||||||
|
sample,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export type FeatureDict = ReturnType<typeof initialize>;
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"pages":[
|
||||||
|
"pages/index/index",
|
||||||
|
"oak#pages/address/list/index",
|
||||||
|
"oak#pages/address/upsert/index"
|
||||||
|
],
|
||||||
|
"window":{
|
||||||
|
"backgroundTextStyle":"light",
|
||||||
|
"navigationBarBackgroundColor": "#fff",
|
||||||
|
"navigationBarTitleText": "Weixin",
|
||||||
|
"navigationBarTextStyle":"black"
|
||||||
|
},
|
||||||
|
"style": "v2",
|
||||||
|
"sitemapLocation": "sitemap.json"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
/**app.wxss**/
|
||||||
|
.container {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 200rpx 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { OakPage, OakComponent } from './init'
|
||||||
|
export interface IAppOption {
|
||||||
|
globalData: {};
|
||||||
|
}
|
||||||
|
|
||||||
|
App<IAppOption>({
|
||||||
|
globalData: {
|
||||||
|
OakPage,
|
||||||
|
OakComponent,
|
||||||
|
},
|
||||||
|
async onLaunch() {
|
||||||
|
console.log('onLaunch');
|
||||||
|
},
|
||||||
|
|
||||||
|
onHide() {
|
||||||
|
console.log('onHide');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { InitializeWechatMp, } from 'oak-frontend-base';
|
||||||
|
import { EntityDict } from 'oak-app-domain/EntityDict';
|
||||||
|
import { storageSchema } from 'oak-app-domain/Storage';
|
||||||
|
|
||||||
|
|
||||||
|
import { triggers, aspectDict, data, checkers, RuntimeContext } from 'oak-general-business';
|
||||||
|
|
||||||
|
const { OakComponent, OakPage } = InitializeWechatMp<EntityDict, RuntimeContext<EntityDict>, typeof aspectDict, {}>(
|
||||||
|
storageSchema,
|
||||||
|
() => ({}),
|
||||||
|
(store) => new RuntimeContext(store, '123'),
|
||||||
|
triggers as any,
|
||||||
|
checkers as any,
|
||||||
|
aspectDict,
|
||||||
|
data as any);
|
||||||
|
export {
|
||||||
|
OakPage,
|
||||||
|
OakComponent,
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"usingComponents": {}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
/** index.wxss **/
|
||||||
|
|
||||||
|
.userinfo {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
color: #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.userinfo-avatar {
|
||||||
|
overflow: hidden;
|
||||||
|
width: 128rpx;
|
||||||
|
height: 128rpx;
|
||||||
|
margin: 20rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.usermotto {
|
||||||
|
margin-top: 200px;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
// index.ts
|
||||||
|
|
||||||
|
Page({
|
||||||
|
data: {
|
||||||
|
motto: 'Hello World',
|
||||||
|
userInfo: {},
|
||||||
|
hasUserInfo: false,
|
||||||
|
canIUse: wx.canIUse('button.open-type.getUserInfo'),
|
||||||
|
canIUseGetUserProfile: false,
|
||||||
|
canIUseOpenData: wx.canIUse('open-data.type.userAvatarUrl') && wx.canIUse('open-data.type.userNickName') // 如需尝试获取用户信息可改为false
|
||||||
|
},
|
||||||
|
// 事件处理函数
|
||||||
|
bindViewTap() {
|
||||||
|
wx.navigateTo({
|
||||||
|
url: '../logs/logs',
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onLoad() {
|
||||||
|
// @ts-ignore
|
||||||
|
if (wx.getUserProfile) {
|
||||||
|
this.setData({
|
||||||
|
canIUseGetUserProfile: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getUserProfile() {
|
||||||
|
// 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认,开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
|
||||||
|
wx.getUserProfile({
|
||||||
|
desc: '展示用户信息', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
|
||||||
|
success: (res) => {
|
||||||
|
console.log(res)
|
||||||
|
this.setData({
|
||||||
|
userInfo: res.userInfo,
|
||||||
|
hasUserInfo: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getUserInfo(e: any) {
|
||||||
|
// 不推荐使用getUserInfo获取用户信息,预计自2021年4月13日起,getUserInfo将不再弹出弹窗,并直接返回匿名的用户个人信息
|
||||||
|
console.log(e)
|
||||||
|
this.setData({
|
||||||
|
userInfo: e.detail.userInfo,
|
||||||
|
hasUserInfo: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
<!--index.wxml-->
|
||||||
|
<view class="container">
|
||||||
|
<view class="userinfo">
|
||||||
|
<block wx:if="{{canIUseOpenData}}">
|
||||||
|
<view class="userinfo-avatar" bindtap="bindViewTap">
|
||||||
|
<open-data type="userAvatarUrl"></open-data>
|
||||||
|
</view>
|
||||||
|
<open-data type="userNickName"></open-data>
|
||||||
|
</block>
|
||||||
|
<block wx:elif="{{!hasUserInfo}}">
|
||||||
|
<button wx:if="{{canIUseGetUserProfile}}" bindtap="getUserProfile"> 获取头像昵称 </button>
|
||||||
|
<button wx:elif="{{canIUse}}" open-type="getUserInfo" bindgetuserinfo="getUserInfo"> 获取头像昵称 </button>
|
||||||
|
<view wx:else> 请使用1.4.4及以上版本基础库 </view>
|
||||||
|
</block>
|
||||||
|
<block wx:else>
|
||||||
|
<image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.avatarUrl}}" mode="cover"></image>
|
||||||
|
<text class="userinfo-nickname">{{userInfo.nickName}}</text>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
<view class="usermotto">
|
||||||
|
<text class="user-motto">{{motto}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
|
||||||
|
"rules": [{
|
||||||
|
"action": "allow",
|
||||||
|
"page": "*"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
export const formatTime = (date: Date) => {
|
||||||
|
const year = date.getFullYear()
|
||||||
|
const month = date.getMonth() + 1
|
||||||
|
const day = date.getDate()
|
||||||
|
const hour = date.getHours()
|
||||||
|
const minute = date.getMinutes()
|
||||||
|
const second = date.getSeconds()
|
||||||
|
|
||||||
|
return (
|
||||||
|
[year, month, day].map(formatNumber).join('/') +
|
||||||
|
' ' +
|
||||||
|
[hour, minute, second].map(formatNumber).join(':')
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatNumber = (n: number) => {
|
||||||
|
const s = n.toString()
|
||||||
|
return s[1] ? s : '0' + s
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"jsx": "preserve",
|
||||||
|
/* Basic Options */
|
||||||
|
// "incremental": true, /* Enable incremental compilation */
|
||||||
|
"target": "esnext", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
|
||||||
|
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||||
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"dom.iterable",
|
||||||
|
"esnext"
|
||||||
|
],
|
||||||
|
// "lib": [], /* Specify library files to be included in the compilation. */
|
||||||
|
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||||
|
// "checkJs": true, /* Report errors in .js files. */
|
||||||
|
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
||||||
|
"declaration": true, /* Generates corresponding '.d.ts' file. */
|
||||||
|
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||||
|
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
||||||
|
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||||
|
"outDir": "lib", /* Redirect output structure to the directory. */
|
||||||
|
"rootDir": "src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||||
|
// "composite": true, /* Enable project compilation */
|
||||||
|
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
||||||
|
// "removeComments": true, /* Do not emit comments to output. */
|
||||||
|
// "noEmit": true, /* Do not emit outputs. */
|
||||||
|
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
||||||
|
"downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||||
|
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||||
|
/* Strict Type-Checking Options */
|
||||||
|
"strict": true, /* Enable all strict type-checking options. */
|
||||||
|
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||||
|
// "strictNullChecks": true, /* Enable strict null checks. */
|
||||||
|
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
||||||
|
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
||||||
|
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
|
||||||
|
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
|
||||||
|
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
||||||
|
/* Additional Checks */
|
||||||
|
// "noUnusedLocals": true, /* Report errors on unused locals. */
|
||||||
|
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
||||||
|
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
||||||
|
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||||
|
/* Module Resolution Options */
|
||||||
|
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||||
|
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
||||||
|
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||||
|
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||||
|
// "typeRoots": [], /* List of folders to include type definitions from. */
|
||||||
|
// "types": [], /* Type declaration files to be included in compilation. */
|
||||||
|
"allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||||
|
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||||
|
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
||||||
|
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||||
|
/* Source Map Options */
|
||||||
|
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
||||||
|
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||||
|
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
||||||
|
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
||||||
|
/* Experimental Options */
|
||||||
|
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
||||||
|
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
||||||
|
/* Advanced Options */
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"resolveJsonModule": true /* Disallow inconsistently-cased references to the same file. */
|
||||||
|
},
|
||||||
|
"include": [ "src/**/*" ],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
]
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue