@tmsfe/tmskit 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +0 -0
- package/README.md +24 -0
- package/dist/index.cjs.js +2248 -0
- package/main.js +3 -0
- package/package.json +72 -0
- package/rollup.config.js +179 -0
- package/src/config/constant.js +65 -0
- package/src/config/defaultTmsConfig.js +17 -0
- package/src/entry.js +20 -0
- package/src/index.js +47 -0
- package/src/init.js +38 -0
- package/src/scripts/create/ask.js +61 -0
- package/src/scripts/create/generator.js +27 -0
- package/src/scripts/create/ignoreFiles.js +7 -0
- package/src/scripts/create/index.js +65 -0
- package/src/scripts/create/render.js +19 -0
- package/src/scripts/run/build/index.js +16 -0
- package/src/scripts/run/dev/index.js +67 -0
- package/src/scripts/run/index.js +57 -0
- package/src/scripts/run/init/index.js +97 -0
- package/src/utils/buildAppJson.js +144 -0
- package/src/utils/checkDependencies.js +77 -0
- package/src/utils/cliUtils.js +35 -0
- package/src/utils/cloneModules.js +90 -0
- package/src/utils/global.js +36 -0
- package/src/utils/io.js +21 -0
- package/src/utils/log.js +44 -0
- package/src/utils/mpCiUtils.js +74 -0
- package/src/utils/npmUtils.js +126 -0
- package/src/utils/tkitUtils.js +84 -0
- package/src/utils/widgets.js +177 -0
- package/src/webpack/base.js +65 -0
- package/src/webpack/build.js +21 -0
- package/src/webpack/buildServer.js +34 -0
- package/src/webpack/dev.js +31 -0
- package/src/webpack/devServer.js +37 -0
- package/src/webpack/plugins/entryExtractPlugin/index.js +29 -0
- package/src/webpack/plugins/px2rpx/index.js +14 -0
- package/src/webpack/utils.js +244 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
const webpackServer = require('../../../webpack/devServer');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const { resolve } = require('../../../utils/widgets');
|
|
4
|
+
const init = require('../init/index');
|
|
5
|
+
const { DEFAULT_MODULE_DIR } = require('../../../config/constant');
|
|
6
|
+
const { tmsModulesMergeLocalModuleCfg } = require('../../../utils/tkitUtils');
|
|
7
|
+
const { checkDependencies } = require('../../../utils/checkDependencies');
|
|
8
|
+
const { fail } = require('../../../utils/log');
|
|
9
|
+
|
|
10
|
+
function isInit(tmsConfig, targetModules, contextDir) {
|
|
11
|
+
// 判断是否存在dist目录
|
|
12
|
+
if (!fs.existsSync(contextDir)) {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
// 判断dist是否存在node_modules
|
|
16
|
+
if (!fs.existsSync(`${contextDir}/node_modules`)) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// 判断dist是否存在miniprogram_npm
|
|
21
|
+
if (!fs.existsSync(`${contextDir}/miniprogram_npm`)) {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// 判断dist是否存在app.json
|
|
26
|
+
if (!fs.existsSync(`${contextDir}/app.json`)) {
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// 判断\源码\dist\是否存在用户指定的模块
|
|
31
|
+
for (const item of targetModules) {
|
|
32
|
+
// 此模块没有root字段(原因:没有merge到module.config.json的配置项。第三方模块的代码可能还没有下载)
|
|
33
|
+
if (!item.root) {
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
// 判断编译目录是否有该模块
|
|
37
|
+
if (!fs.existsSync(`${contextDir}/${item.root}`)) {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
// 判断源码目录是否有该模块
|
|
41
|
+
if (item.path && !fs.existsSync(resolve(item.path))) {
|
|
42
|
+
fail(`${item.path}模块代码路径不存在, 请检查tms.config.js的${item.name}模块的path`);
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// 判断package.json的版本是否有新的版本
|
|
48
|
+
return checkDependencies(targetModules, resolve('./'), tmsConfig.webpack.outputDir);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function dev(tmsConfig, targetModules, env) {
|
|
52
|
+
// tms.config.js的modules 合并 module.config.json的配置项
|
|
53
|
+
let newModules = tmsModulesMergeLocalModuleCfg(targetModules, tmsConfig.appName, DEFAULT_MODULE_DIR);
|
|
54
|
+
|
|
55
|
+
// 判断是否进行init命令
|
|
56
|
+
if (isInit(tmsConfig, newModules, resolve('dist'))) {
|
|
57
|
+
// init函数会将 最新的tms.config.js的modules 合并 module.config.json的配置项 返回,不需要再做重复工作
|
|
58
|
+
const initData = await init(tmsConfig, targetModules);
|
|
59
|
+
newModules = initData.targetModules;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
console.log('当前dev启动的有效模块', newModules.map(item => item.name));
|
|
63
|
+
webpackServer(tmsConfig, newModules, env);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
module.exports = dev;
|
|
67
|
+
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
const init = require('./init/index');
|
|
2
|
+
const dev = require('./dev/index');
|
|
3
|
+
const build = require('./build/index');
|
|
4
|
+
const { createTask } = require('../../utils/widgets');
|
|
5
|
+
const { MODE } = require('../../config/constant');
|
|
6
|
+
const { readTmsConfig, checkModules } = require('../../utils/tkitUtils');
|
|
7
|
+
|
|
8
|
+
const handleModulesArg = (cmd) => {
|
|
9
|
+
// 主模块开发
|
|
10
|
+
if (cmd.module === MODE.main) {
|
|
11
|
+
return MODE.main;
|
|
12
|
+
}
|
|
13
|
+
// 单模块 或 多模块开发
|
|
14
|
+
if (cmd.module) {
|
|
15
|
+
return [
|
|
16
|
+
cmd.module,
|
|
17
|
+
...cmd.args,
|
|
18
|
+
];
|
|
19
|
+
}
|
|
20
|
+
// 全量模块
|
|
21
|
+
return MODE.all;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
async function run(commandName, cmd) {
|
|
25
|
+
const moduleArg = handleModulesArg(cmd);
|
|
26
|
+
const { env } = cmd;
|
|
27
|
+
|
|
28
|
+
const tmsConfig = await createTask(readTmsConfig, '开始读取脚手架的配置项', '读取脚手架的配置项完成')(env);
|
|
29
|
+
|
|
30
|
+
let modules;
|
|
31
|
+
// 主模块
|
|
32
|
+
if (moduleArg === MODE.main) {
|
|
33
|
+
modules = checkModules(tmsConfig, [...new Set([...tmsConfig.mainPackages])]);;
|
|
34
|
+
} else if (moduleArg === MODE.all) {
|
|
35
|
+
// 全量模块
|
|
36
|
+
modules = tmsConfig.modules;
|
|
37
|
+
} else {
|
|
38
|
+
// 检查用户输入modules的有效性
|
|
39
|
+
modules = checkModules(tmsConfig, [...new Set([...tmsConfig.mainPackages, ...moduleArg])]);;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
switch (commandName) {
|
|
43
|
+
case 'init':
|
|
44
|
+
init(tmsConfig, modules, env);
|
|
45
|
+
return;
|
|
46
|
+
case 'dev':
|
|
47
|
+
dev(tmsConfig, modules, env);
|
|
48
|
+
return;
|
|
49
|
+
case 'build':
|
|
50
|
+
build(tmsConfig, modules, env);
|
|
51
|
+
return;
|
|
52
|
+
default:
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
module.exports = run;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
const shelljs = require('shelljs');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const io = require('../../../utils/io');
|
|
4
|
+
const { resolve, createTask } = require('../../../utils/widgets');
|
|
5
|
+
const { buildOutputAppJson } = require('../../../utils/buildAppJson');
|
|
6
|
+
const { npmInstallAll } = require('../../../utils/npmUtils');
|
|
7
|
+
const { buildMpNpm } = require('../../../utils/mpCiUtils');
|
|
8
|
+
const { MODULE_CODE_DIR, CACHE_DIR, DEFAULT_COPY_CONFIG, DEFAULT_MODULE_DIR } = require('../../../config/constant');
|
|
9
|
+
const { cloneModules } = require('../../../utils/cloneModules');
|
|
10
|
+
const { tmsModulesMergeLocalModuleCfg } = require('../../../utils/tkitUtils');
|
|
11
|
+
const { fail } = require('../../../utils/log');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 拷贝package.json\模块的代码到编译输出目录
|
|
15
|
+
* @param { object } tmsConfig
|
|
16
|
+
* @param { array } modules
|
|
17
|
+
* @param { array } defaultFiles 默认需要拷贝的配置项
|
|
18
|
+
* @returns
|
|
19
|
+
*/
|
|
20
|
+
const cpFilesToOutput = function (tmsConfig, targetModules, defaultFiles) {
|
|
21
|
+
const outputDir = resolve(tmsConfig.webpack.outputDir);
|
|
22
|
+
io.ensureDirExist(outputDir);
|
|
23
|
+
defaultFiles.forEach((item) => {
|
|
24
|
+
if (fs.existsSync(resolve(item))) {
|
|
25
|
+
shelljs.cp('-rf', resolve(item), resolve(tmsConfig.webpack.outputDir, item));
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// 拷贝模块的代码到编译输出目录
|
|
30
|
+
targetModules.forEach((item) => {
|
|
31
|
+
const outputModuleDir = resolve(`${tmsConfig.webpack.outputDir}/${item.root}`);
|
|
32
|
+
if (!fs.existsSync(resolve(item.path))) {
|
|
33
|
+
fail(`${item.path}模块代码路径不存在, 请检查tms.config.js的${item.name}模块的path`);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
if (!fs.existsSync(outputModuleDir)) {
|
|
37
|
+
shelljs.mkdir('-p', outputModuleDir);
|
|
38
|
+
} else {
|
|
39
|
+
// 删除除了node_modules、miniprogram_npm 的其他文件
|
|
40
|
+
// eslint-disable-next-line
|
|
41
|
+
shelljs.exec('find . -not \( -name node_modules -or -name miniprogram_npm \) -delete', { silent: true });
|
|
42
|
+
}
|
|
43
|
+
shelljs.cp('-Rf', `${resolve(item.path)}/*`, outputModuleDir);
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
async function task(tmsConfig, targetModules) {
|
|
48
|
+
// 下载和移动代码
|
|
49
|
+
await createTask(
|
|
50
|
+
cloneModules,
|
|
51
|
+
'开始下载模块代码完成',
|
|
52
|
+
'下载模块代码码完成',
|
|
53
|
+
)(MODULE_CODE_DIR, resolve('./'), targetModules);
|
|
54
|
+
|
|
55
|
+
// tms.config.js的modules 合并 module.config.json的配置项
|
|
56
|
+
const newModules = tmsModulesMergeLocalModuleCfg(targetModules, tmsConfig.appName, DEFAULT_MODULE_DIR);
|
|
57
|
+
console.log('当前init的有效模块', newModules.map(item => item.name));
|
|
58
|
+
|
|
59
|
+
// 拷贝相关配置文件到输出目录
|
|
60
|
+
await createTask(
|
|
61
|
+
cpFilesToOutput,
|
|
62
|
+
'开始拷贝文件到编译输出目录',
|
|
63
|
+
'拷贝文件到编译输出目录完成',
|
|
64
|
+
)(tmsConfig, newModules, DEFAULT_COPY_CONFIG);
|
|
65
|
+
|
|
66
|
+
// npm install
|
|
67
|
+
await createTask(
|
|
68
|
+
npmInstallAll,
|
|
69
|
+
'开始npm install',
|
|
70
|
+
'npm install 完成',
|
|
71
|
+
)(newModules, resolve(tmsConfig.webpack.outputDir), `${CACHE_DIR}/node_modules`);
|
|
72
|
+
|
|
73
|
+
// 构建miniprograme_npm
|
|
74
|
+
await createTask(
|
|
75
|
+
buildMpNpm,
|
|
76
|
+
'开始构建miniprograme_npm',
|
|
77
|
+
'构建miniprograme_npm 完成',
|
|
78
|
+
)({ appId: tmsConfig.appId, projectPath: resolve('./'), privateKey: tmsConfig.privateKey });
|
|
79
|
+
|
|
80
|
+
// 动态生成编译后的app.json;
|
|
81
|
+
await createTask(
|
|
82
|
+
buildOutputAppJson,
|
|
83
|
+
'开始生成编译后的app.json',
|
|
84
|
+
'生成编译后的app.json完成',
|
|
85
|
+
)(tmsConfig, newModules);
|
|
86
|
+
|
|
87
|
+
return newModules;
|
|
88
|
+
}
|
|
89
|
+
async function bootstrap(tmsConfig, targetModules) {
|
|
90
|
+
const newModules = await task(tmsConfig, targetModules);
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
targetModules: newModules,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
module.exports = bootstrap;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const { DEFAULT_MODULE_DIR, MODULE_CONFIG_FILENAME } = require('../config/constant');
|
|
3
|
+
const { fail } = require('./log');
|
|
4
|
+
const { resolve, isObject, isArray } = require('./widgets');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 获取每个模块下面的信息,并且收集,后续更新到appJson里面
|
|
8
|
+
* @param { object } file 操作目录下面所有的文件
|
|
9
|
+
* @param { string } appName 小程序的名称
|
|
10
|
+
*/
|
|
11
|
+
function setModuleConfig(file, appName, moduleDir) {
|
|
12
|
+
const content = file.contents ? JSON.parse(file.contents.toString()) : JSON.parse(file);
|
|
13
|
+
|
|
14
|
+
if (isObject(content)) {
|
|
15
|
+
content.root = content.root.indexOf(moduleDir) > -1 ? content.root : `${moduleDir}/${content.root}`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (isArray(content)) {
|
|
19
|
+
let i = content.length - 1;
|
|
20
|
+
while (i >= 0) {
|
|
21
|
+
let current = content[i];
|
|
22
|
+
current.root = current.root.indexOf(moduleDir) > -1 ? current.root : `${moduleDir}/${current.root}`;
|
|
23
|
+
|
|
24
|
+
if (appName && current.mpConfig && current.mpConfig[appName]) {
|
|
25
|
+
current = { ...current, ...current.mpConfig[appName] };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
delete current.mpConfig;
|
|
29
|
+
delete current.isSubpackages;
|
|
30
|
+
|
|
31
|
+
content[i] = current;
|
|
32
|
+
i--; // eslint-disable-line
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return content;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* 递归获取本地所有模块的配置信息
|
|
40
|
+
*/
|
|
41
|
+
function getLocalModuleConfig(modules = [], appName, moduleDir, moduleConfigFilename) {
|
|
42
|
+
const modulesConfig = {};
|
|
43
|
+
|
|
44
|
+
modules.forEach(({ path }) => {
|
|
45
|
+
const moduleConfigPath = resolve(path, moduleConfigFilename);
|
|
46
|
+
if (fs.existsSync(moduleConfigPath)) {
|
|
47
|
+
const content = fs.readFileSync(moduleConfigPath, 'utf-8');
|
|
48
|
+
modulesConfig[moduleConfigPath] = setModuleConfig(content, appName, moduleDir);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
return modulesConfig;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* 更新appJson里面的首页配置
|
|
56
|
+
* @param { object } appJson appJson信息
|
|
57
|
+
* @param { array } mainPackages 小程序主包信息
|
|
58
|
+
* @returns { object } appJson小程序主页配置信息
|
|
59
|
+
*/
|
|
60
|
+
function updateMainPackages(appJson, mainPackages = []) {
|
|
61
|
+
let foundMainPackages = appJson.subpackages.filter(subpackage => mainPackages.includes(subpackage.name));
|
|
62
|
+
if (foundMainPackages.length === 0) {
|
|
63
|
+
// 没找到主包
|
|
64
|
+
foundMainPackages = [appJson.subpackages[0]];
|
|
65
|
+
}
|
|
66
|
+
// 拼装 app.pages
|
|
67
|
+
foundMainPackages.forEach((subpackage) => {
|
|
68
|
+
if (!subpackage.pages || !subpackage.pages.length) {
|
|
69
|
+
fail(`主包 ${subpackage} 不能没有 pages`);
|
|
70
|
+
process.exit(-1);
|
|
71
|
+
}
|
|
72
|
+
subpackage.pages.forEach((page) => {
|
|
73
|
+
appJson.pages.push(`${subpackage.root}/${page}`);
|
|
74
|
+
});
|
|
75
|
+
if (subpackage.plugins) {
|
|
76
|
+
Object.assign(appJson.plugins, subpackage.plugins);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// 去掉 subpackages 中的主包配置
|
|
81
|
+
const foundMainPackageNames = foundMainPackages.map(item => item.name);
|
|
82
|
+
// eslint-disable-next-line
|
|
83
|
+
appJson.subpackages = appJson.subpackages.filter(subpackage => !foundMainPackageNames.includes(subpackage.name));
|
|
84
|
+
|
|
85
|
+
return appJson;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* 获取app.json内容
|
|
89
|
+
* @param {string} sourceAppJsonPath
|
|
90
|
+
* @returns
|
|
91
|
+
*/
|
|
92
|
+
const getAppJsonContent = (sourceAppJsonPath) => {
|
|
93
|
+
if (!fs.existsSync(sourceAppJsonPath)) {
|
|
94
|
+
fail(`当前路径 ${sourceAppJsonPath} 没找到app.json`);
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
const appJson = JSON.parse(fs.readFileSync(sourceAppJsonPath), 'utf-8');
|
|
98
|
+
// 加入默认值
|
|
99
|
+
appJson.subpackages = [];
|
|
100
|
+
appJson.pages = [];
|
|
101
|
+
appJson.plugins = {};
|
|
102
|
+
delete appJson.entranceDeclare;
|
|
103
|
+
return appJson;
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* 更新app.json中的subpackages
|
|
107
|
+
* @param {Object} appJson
|
|
108
|
+
* @param {Object} modulesConfig
|
|
109
|
+
*/
|
|
110
|
+
const updateSubpackages = (appJson, modulesConfig) => {
|
|
111
|
+
// eslint-disable-next-line
|
|
112
|
+
for (const name in modulesConfig) {
|
|
113
|
+
const moduleInfo = isObject(modulesConfig[name]) ? [modulesConfig[name]] : modulesConfig[name];
|
|
114
|
+
// eslint-disable-next-line
|
|
115
|
+
appJson.subpackages = appJson.subpackages.concat(moduleInfo);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* 动态生成编译后的app.json
|
|
122
|
+
* @param {object} tmsConfig
|
|
123
|
+
* @param {array} modules
|
|
124
|
+
* @returns
|
|
125
|
+
*/
|
|
126
|
+
function buildOutputAppJson(tmsConfig, modules) {
|
|
127
|
+
// 获取当前 modules 下的所有子模块的配置内容
|
|
128
|
+
const modulesConfig = getLocalModuleConfig(modules, tmsConfig.appName, DEFAULT_MODULE_DIR, MODULE_CONFIG_FILENAME);
|
|
129
|
+
// 获取app.json的配置
|
|
130
|
+
const appJson = getAppJsonContent(resolve('./app.json'));
|
|
131
|
+
// 更新app.json中的subpackages
|
|
132
|
+
updateSubpackages(appJson, modulesConfig);
|
|
133
|
+
// 更新主包,需在subpackages处理完成后执行, pages/
|
|
134
|
+
updateMainPackages(appJson, tmsConfig.mainPackages, DEFAULT_MODULE_DIR);
|
|
135
|
+
|
|
136
|
+
fs.writeFileSync(resolve(`${tmsConfig.webpack.outputDir}/app.json`), JSON.stringify(appJson, null, 2), 'utf8');
|
|
137
|
+
|
|
138
|
+
return appJson;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
module.exports = {
|
|
142
|
+
setModuleConfig,
|
|
143
|
+
buildOutputAppJson,
|
|
144
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const semver = require('semver');
|
|
3
|
+
const { resolve } = require('./widgets');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { fail } = require('./log');
|
|
6
|
+
const shelljs = require('shelljs');
|
|
7
|
+
|
|
8
|
+
const getLatestVersion = (npmName) => {
|
|
9
|
+
const data = shelljs.exec(`npm view ${npmName} version`);
|
|
10
|
+
return data.stdout || '0.0.0';
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 检查package.json的依赖大于node_module的版本,则返回true
|
|
15
|
+
* @param {*} modules 模块
|
|
16
|
+
* @param {*} cwd 待检查package.json所在的目录 (eg: 当前执行脚本的目录)
|
|
17
|
+
* @param {*} outputDir 待检查node_modules存放的目录 (eg: dist/node_modules)
|
|
18
|
+
* @returns
|
|
19
|
+
*/
|
|
20
|
+
const checkDependencies = (modules, cwd, outputDir) => {
|
|
21
|
+
// 步骤1. 收集package.json
|
|
22
|
+
const packageJsonName = 'package.json'; // 查找文件名
|
|
23
|
+
// 1.1根目录的package.json
|
|
24
|
+
const packageArr = [
|
|
25
|
+
{
|
|
26
|
+
srcPackageDir: path.join(cwd, packageJsonName),
|
|
27
|
+
destNpmDir: resolve(outputDir, 'node_modules'),
|
|
28
|
+
},
|
|
29
|
+
];
|
|
30
|
+
// 1.2模块的package.json
|
|
31
|
+
modules.forEach((item) => {
|
|
32
|
+
const srcPackageDir = path.join(cwd, item.path, 'package.json');
|
|
33
|
+
if (fs.existsSync(srcPackageDir)) {
|
|
34
|
+
packageArr.push({
|
|
35
|
+
srcPackageDir,
|
|
36
|
+
destNpmDir: resolve(outputDir, item.root, 'node_modules'),
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// 步骤2. 比较package.json的依赖与node_modules依赖的版本号
|
|
42
|
+
for (const item of packageArr) {
|
|
43
|
+
const packageJson = fs.readFileSync(item.srcPackageDir, 'utf-8');
|
|
44
|
+
let dependencies;
|
|
45
|
+
try {
|
|
46
|
+
dependencies = JSON.parse(packageJson).dependencies;
|
|
47
|
+
} catch (e) {
|
|
48
|
+
fail(`解析${packageJson}报错,请检查是否是正确的json配置项`);
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
const dependenciesKeys = Object.keys(dependencies);
|
|
52
|
+
for (const key of dependenciesKeys) {
|
|
53
|
+
const depPath = path.join(item.destNpmDir, key);
|
|
54
|
+
if (!fs.existsSync(depPath)) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
const depPackagePath = path.join(depPath, 'package.json');
|
|
58
|
+
if (fs.existsSync(depPackagePath)) {
|
|
59
|
+
const packageData = require(depPackagePath);
|
|
60
|
+
if (dependencies[key] === 'latest') {
|
|
61
|
+
dependencies[key] = getLatestVersion(key);
|
|
62
|
+
}
|
|
63
|
+
if (packageData.version === 'latest') {
|
|
64
|
+
packageData.version = getLatestVersion(key);
|
|
65
|
+
}
|
|
66
|
+
if (semver.lt(packageData.version, semver.minVersion(dependencies[key]).version)) {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return false;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
module.exports = {
|
|
76
|
+
checkDependencies,
|
|
77
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const cp = require('child_process');
|
|
3
|
+
|
|
4
|
+
const getDevtoolCliPath = async () => {
|
|
5
|
+
let cliPath;
|
|
6
|
+
if (process.platform === 'darwin') {
|
|
7
|
+
cliPath = '/Applications/wechatwebdevtools.app/Contents/MacOS/cli';
|
|
8
|
+
} else if (process.platform === 'win32') {
|
|
9
|
+
cliPath = 'C:/Program Files (x86)/Tencent/微信web开发者工具/cli.bat';
|
|
10
|
+
} else {
|
|
11
|
+
// 其余平台暂不支持
|
|
12
|
+
throw new Error('unsupported platform');
|
|
13
|
+
}
|
|
14
|
+
const exists = await new Promise(resolve => fs.exists(cliPath, resolve));
|
|
15
|
+
if (!exists) {
|
|
16
|
+
// 找不到开发工具
|
|
17
|
+
throw new Error(`未找到微信小程序开发者工具,请确认是否安装,如未安装请前往
|
|
18
|
+
https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html 下载`);
|
|
19
|
+
}
|
|
20
|
+
return cliPath;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const openDevtool = async (path) => {
|
|
24
|
+
const cliPath = await getDevtoolCliPath();
|
|
25
|
+
const child = cp.spawn(cliPath, ['open', '--project', path], {
|
|
26
|
+
detached: true,
|
|
27
|
+
stdio: 'inherit',
|
|
28
|
+
});
|
|
29
|
+
child.unref();
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
module.exports = {
|
|
33
|
+
getDevtoolCliPath,
|
|
34
|
+
openDevtool,
|
|
35
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
const MetalSmith = require('metalsmith');
|
|
2
|
+
const { getGlobalInstance } = require('./global.js');
|
|
3
|
+
const { downloadRepoForGit, resolve } = require('./widgets');
|
|
4
|
+
const { fail } = require('./log');
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const shelljs = require('shelljs');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 对克隆下来的模块进行相应的文件处理操作,比如收集处理模块信息,进行信息缓存等操作
|
|
10
|
+
* @param { string } sourceDir 缓存文件夹
|
|
11
|
+
* @param { string } targetDir 目标文件夹
|
|
12
|
+
* @param { arrary } ignore
|
|
13
|
+
* @returns { undefined } no return
|
|
14
|
+
*/
|
|
15
|
+
function moveFile(sourceDir, targetDir, ignore = []) {
|
|
16
|
+
// 删除不是文件夹的文件
|
|
17
|
+
return new Promise((resolve) => {
|
|
18
|
+
MetalSmith(__dirname)
|
|
19
|
+
.ignore(ignore)
|
|
20
|
+
.source(sourceDir)
|
|
21
|
+
.destination(targetDir)
|
|
22
|
+
.build((e) => {
|
|
23
|
+
if (e) {
|
|
24
|
+
fail(e); // eslint-disable-line
|
|
25
|
+
console.log('MetalSmith 详细的错误信息:', e);
|
|
26
|
+
}
|
|
27
|
+
resolve();
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* 下载目标模块
|
|
34
|
+
* @param { string } sourceDir 缓存文件夹
|
|
35
|
+
* @param { string } targetDir 目标文件夹
|
|
36
|
+
* @returns { array } modules 描述模块的列表
|
|
37
|
+
*/
|
|
38
|
+
async function cloneModules(sourceDir, targetDir, modules) {
|
|
39
|
+
// 根据小程序的配置文件下载模块, 并且处理信息
|
|
40
|
+
for (const moduleInfo of modules) { // eslint-disable-line
|
|
41
|
+
if (moduleInfo.repoInfo) {
|
|
42
|
+
await downLoadAndMoveModule(sourceDir, targetDir, moduleInfo);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 下载模块信息并且将它移动到对应的位置
|
|
49
|
+
* @param { string } sourceDir 代码缓存文件夹
|
|
50
|
+
* @param { string } targetDir 代码要放到的目标文件夹
|
|
51
|
+
* @returns { array } moduleInfo 描述模块的信息
|
|
52
|
+
*/
|
|
53
|
+
async function downLoadAndMoveModule(sourceDir, targetDir, moduleInfo) {
|
|
54
|
+
const { repoInfo: { buildGitTag, httpRepoUrl }, path } = moduleInfo;
|
|
55
|
+
|
|
56
|
+
// 源码临时存在的源目录
|
|
57
|
+
let sourcePath = resolve(sourceDir, path);
|
|
58
|
+
// 源码要放到目标目录
|
|
59
|
+
const targetPath = resolve(targetDir, path);
|
|
60
|
+
// 设置模块的构建分支
|
|
61
|
+
const cloneBranch = buildGitTag && typeof buildGitTag === 'string' ? buildGitTag : 'master';
|
|
62
|
+
|
|
63
|
+
// 检查缓存中有没有
|
|
64
|
+
const globalInstance = getGlobalInstance();
|
|
65
|
+
const moduleInCache = globalInstance.getModuleCache(httpRepoUrl, cloneBranch);
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
if (!moduleInCache) {
|
|
69
|
+
await downloadRepoForGit(httpRepoUrl, sourcePath, cloneBranch);
|
|
70
|
+
globalInstance.setModuleCache(httpRepoUrl, cloneBranch, sourcePath);
|
|
71
|
+
} else {
|
|
72
|
+
sourcePath = globalInstance.getModuleCache(httpRepoUrl, cloneBranch).dest;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (fs.existsSync(targetPath)) {
|
|
76
|
+
shelljs.rm('-rf', targetPath);
|
|
77
|
+
}
|
|
78
|
+
await moveFile(sourcePath, targetPath, [
|
|
79
|
+
'node_modules',
|
|
80
|
+
'.git',
|
|
81
|
+
]);
|
|
82
|
+
} catch (e) {
|
|
83
|
+
fail(`downLoadAndMoveModule ${e}`); // eslint-disable-line
|
|
84
|
+
process.exit(-1);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
module.exports = {
|
|
89
|
+
cloneModules,
|
|
90
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
class Globale {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.moduleCache = {};
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
setModuleCache(url, branch, dest) {
|
|
7
|
+
const instance = getGlobalInstance();
|
|
8
|
+
|
|
9
|
+
const key = `${branch}:${url}`;
|
|
10
|
+
|
|
11
|
+
instance.moduleCache[key] = {
|
|
12
|
+
dest,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
return instance.moduleCache[key];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
getModuleCache(url, branch) {
|
|
19
|
+
const instance = getGlobalInstance();
|
|
20
|
+
|
|
21
|
+
return instance.moduleCache[`${branch}:${url}`];
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let instance;
|
|
26
|
+
function getGlobalInstance() {
|
|
27
|
+
if (instance) {
|
|
28
|
+
return instance;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return instance = new Globale();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
module.exports = {
|
|
35
|
+
getGlobalInstance,
|
|
36
|
+
};
|
package/src/utils/io.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
/**
|
|
3
|
+
* 判断目录是否为空
|
|
4
|
+
* @param {string} dirname 目录名
|
|
5
|
+
* @returns
|
|
6
|
+
*/
|
|
7
|
+
const isDirEmpty = dirname => fs.promises.readdir(dirname).then(files => files.length === 0);
|
|
8
|
+
/**
|
|
9
|
+
* 确保目录存在,不存在就创建一个
|
|
10
|
+
* @param {*} dirname 目录名
|
|
11
|
+
*/
|
|
12
|
+
const ensureDirExist = (dirname) => {
|
|
13
|
+
if (!fs.existsSync(dirname)) {
|
|
14
|
+
fs.mkdirSync(dirname, { recursive: true });
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
module.exports = {
|
|
19
|
+
isDirEmpty,
|
|
20
|
+
ensureDirExist,
|
|
21
|
+
};
|
package/src/utils/log.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 本文件提供无依赖的在终端打印彩色文字的方法。
|
|
5
|
+
*/
|
|
6
|
+
const resetCfg = decodeURIComponent('%1B%5B0m'); // \033[0m转义后的字符按,用来还原属性
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 打印红底黑字格式的文字
|
|
10
|
+
* @param {String} message 需要打印的文字信息
|
|
11
|
+
* @returns {undefined} 无
|
|
12
|
+
*/
|
|
13
|
+
const fail = (message = '') => {
|
|
14
|
+
const redStyleConfig = decodeURIComponent('%1B%5B41%3B30m'); // \033[41;30m转义后的字符按,console时输出红色文字
|
|
15
|
+
const greenFontStyleConfig = decodeURIComponent('%1B%5B41%3B37m'); // \033[41;30m转义后的字符按,console时输出红底白色文字
|
|
16
|
+
console.log(`${redStyleConfig} ERROR ${greenFontStyleConfig} ${message}${resetCfg}`); // eslint-disable-line no-console
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 打印绿底黑字格式的文字
|
|
21
|
+
* @param {String} message 需要打印的文字信息
|
|
22
|
+
* @returns {undefined} 无
|
|
23
|
+
*/
|
|
24
|
+
const succeed = (message = '') => {
|
|
25
|
+
const greenStyleConfig = decodeURIComponent('%1B%5B42%3B30m'); // \033[42;30m转义后的字符按,console时输出绿色文字
|
|
26
|
+
const greenFontStyleConfig = decodeURIComponent('%1B%5B40%3B32m'); // \033[40;32m转义后的字符按,console时输出绿色文字
|
|
27
|
+
console.log(`${greenStyleConfig} Success ${greenFontStyleConfig} ${message}${resetCfg}`); // eslint-disable-line no-console
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 打印warn提示
|
|
33
|
+
* @param {String} message 需要打印的文字信息
|
|
34
|
+
* @returns {undefined} 无
|
|
35
|
+
*/
|
|
36
|
+
const warn = (message) => {
|
|
37
|
+
console.log(chalk.yellow(message));
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
module.exports = {
|
|
41
|
+
fail,
|
|
42
|
+
succeed,
|
|
43
|
+
warn,
|
|
44
|
+
};
|