oak-cli 项目新建
This commit is contained in:
parent
8511d289be
commit
430dace767
|
|
@ -83,4 +83,6 @@ dist
|
|||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.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