@tmsfe/tmskit 0.0.7 → 0.0.8
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/README.md +27 -27
- package/dist/index.cjs.js +1284 -983
- package/package.json +73 -75
- package/src/{gulp → compile}/build.js +5 -5
- package/src/{gulp → compile}/compile.js +90 -81
- package/src/{gulp → compile}/dev.js +129 -102
- package/src/{gulp → compile}/plugins/less.js +116 -116
- package/src/{gulp → compile}/plugins/mpCommonDep.js +131 -131
- package/src/{gulp → compile}/plugins/mpJsonDep.js +112 -108
- package/src/{gulp → compile}/plugins/mpWxmlDep.js +194 -194
- package/src/{gulp → compile}/plugins/postcss-font-base64.js +72 -72
- package/src/{gulp → compile}/plugins/replaceEnv.js +29 -29
- package/src/{gulp → compile}/plugins/utils/pluginError.js +25 -25
- package/src/config/constant.js +69 -71
- package/src/config/defaultTmsConfig.js +16 -16
- package/src/{utils → core}/buildAppJson.js +166 -221
- package/src/{utils → core}/checkDependencies.js +77 -77
- package/src/core/cloneModules.js +203 -0
- package/src/{utils → core}/handleError.js +18 -16
- package/src/core/isInIt.js +69 -0
- package/src/{utils/mpCiUtils.js → core/mpCi.js} +73 -73
- package/src/core/npm.js +218 -0
- package/src/core/symbolicLink.js +24 -0
- package/src/{utils/tkitUtils.js → core/tmsMpconfig.js} +234 -158
- package/src/entry.js +62 -60
- package/src/index.js +63 -62
- package/src/init.js +33 -33
- package/src/scripts/create/ask.js +63 -63
- package/src/scripts/create/generator.js +25 -25
- package/src/scripts/create/ignoreFiles.js +7 -7
- package/src/scripts/create/index.js +72 -72
- package/src/scripts/create/render.js +19 -19
- package/src/scripts/run/build/index.js +16 -17
- package/src/scripts/run/dev/index.js +42 -84
- package/src/scripts/run/index.js +97 -68
- package/src/scripts/run/init/index.js +95 -87
- package/src/scripts/run/install/index.js +31 -29
- package/src/utils/findCssImport.js +30 -30
- package/src/utils/global.js +22 -36
- package/src/utils/io.js +107 -106
- package/src/utils/log.js +47 -44
- package/src/utils/widgets.js +178 -167
- package/main.js +0 -3
- package/src/utils/cliUtils.js +0 -35
- package/src/utils/cloneModules.js +0 -116
- package/src/utils/npmUtils.js +0 -166
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 下载第三方代码
|
|
3
|
+
*/
|
|
4
|
+
const MetalSmith = require('metalsmith');
|
|
5
|
+
const crypto = require('crypto');
|
|
6
|
+
const { downloadRepoForGit, pullRepoForGit, resolve } = require('../utils/widgets');
|
|
7
|
+
const { fail, info } = require('../utils/log');
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const shelljs = require('shelljs');
|
|
10
|
+
const { handleError } = require('./handleError');
|
|
11
|
+
const { global } = require('../utils/global');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 处理用户没有clone git仓库权限问题,拼接tms.private.config.js的账号信息
|
|
15
|
+
* @param {*} httpRepoUrl
|
|
16
|
+
* @param {*} moduleName
|
|
17
|
+
* @returns
|
|
18
|
+
*/
|
|
19
|
+
function replaceGitUrlAccount(httpRepoUrl, moduleName) {
|
|
20
|
+
// 用户本地的私有项目配置(用来配置环境\模块信息\账号信息)
|
|
21
|
+
const tmsPrivateCf = global.getData('tmsPrivateCf');
|
|
22
|
+
|
|
23
|
+
let gitUrl = httpRepoUrl;
|
|
24
|
+
const { username = '', pass = '' } = tmsPrivateCf?.gitAccout?.[moduleName] || {};
|
|
25
|
+
|
|
26
|
+
const urlPrefixReg = /http(s)?:\/\//;
|
|
27
|
+
if (username && pass && urlPrefixReg.test(gitUrl)) {
|
|
28
|
+
gitUrl = gitUrl.replace(urlPrefixReg, val => `${val}${encodeURIComponent(username)}:${pass}@`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return gitUrl;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 对克隆下来的模块进行相应的文件处理操作,比如收集处理模块信息,进行信息缓存等操作
|
|
36
|
+
* @param { string } sourceDir 缓存文件夹
|
|
37
|
+
* @param { string } targetDir 目标文件夹
|
|
38
|
+
* @param { arrary } ignore
|
|
39
|
+
* @returns { undefined } no return
|
|
40
|
+
*/
|
|
41
|
+
function moveFile(sourceDir, targetDir, ignore = []) {
|
|
42
|
+
// 删除不是文件夹的文件
|
|
43
|
+
return new Promise((resolve, reject) => {
|
|
44
|
+
MetalSmith(__dirname)
|
|
45
|
+
.ignore(ignore)
|
|
46
|
+
.source(sourceDir)
|
|
47
|
+
.destination(targetDir)
|
|
48
|
+
.build((e) => {
|
|
49
|
+
if (e) {
|
|
50
|
+
fail(`${sourceDir} moveFile ${targetDir}出现错误: ${e}`);
|
|
51
|
+
reject(e);
|
|
52
|
+
}
|
|
53
|
+
resolve();
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 根据gitUrl 和 branch取md5值
|
|
60
|
+
* @param {*} gitUrl
|
|
61
|
+
* @param {*} branch
|
|
62
|
+
* @returns
|
|
63
|
+
*/
|
|
64
|
+
function md5ByGitUrlBranch(gitUrl, branch) {
|
|
65
|
+
const newBranch = branch && typeof branch === 'string' ? branch : 'master';
|
|
66
|
+
return crypto.createHash('md5').update(JSON.stringify({ gitUrl, branch: newBranch }))
|
|
67
|
+
.digest('hex');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 下载目标模块
|
|
72
|
+
* @param { string } sourceDir 缓存文件夹
|
|
73
|
+
* @param { string } targetDir 目标文件夹
|
|
74
|
+
* @returns { array } modules 描述模块的列表
|
|
75
|
+
*/
|
|
76
|
+
async function cloneModules(sourceDir, targetDir, modules) {
|
|
77
|
+
// 收集下载模块代码的任务
|
|
78
|
+
const downloadTasksMap = collectDownLoadTasksMap(sourceDir, targetDir, modules);
|
|
79
|
+
|
|
80
|
+
// 开始执行下载和移动代码的任务
|
|
81
|
+
const arrPromises = [];
|
|
82
|
+
downloadTasksMap.forEach(({ promiseTask, params, callbacks }) => {
|
|
83
|
+
arrPromises.push(promiseTask(...Object.keys(params).map(key => params[key]))
|
|
84
|
+
.then(async () => {
|
|
85
|
+
const callArr = callbacks.map(async ({
|
|
86
|
+
params: cParams,
|
|
87
|
+
fn,
|
|
88
|
+
}) => fn(...Object.keys(cParams).map(key => cParams[key])));
|
|
89
|
+
return Promise.all(callArr);
|
|
90
|
+
})
|
|
91
|
+
.catch((e) => {
|
|
92
|
+
handleError(`下载代码${params.httpRepoUrl}出现错误:${e}`);
|
|
93
|
+
}));
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
await Promise.all(arrPromises);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* 收集下载模块代码的任务
|
|
101
|
+
* @param { string } sourceDir 代码缓存文件夹
|
|
102
|
+
* @param { string } targetDir 代码要放到的目标文件夹
|
|
103
|
+
* @returns { array } modules 描述模块的列表
|
|
104
|
+
*/
|
|
105
|
+
function collectDownLoadTasksMap(sourceDir, targetDir, modules) {
|
|
106
|
+
// 下载代码任务 Map (key解释 缓存代码路径/md5(gitUrl,branch)
|
|
107
|
+
// {
|
|
108
|
+
// '/Users/odile/.tmskit/modules_code/026cb72509c2369dbd75779181f820bc': {
|
|
109
|
+
// promiseTask, 下载代码的任务
|
|
110
|
+
// params: { 下载代码时的参数
|
|
111
|
+
// gitUrl,
|
|
112
|
+
// sourcePath,
|
|
113
|
+
// branch,
|
|
114
|
+
// },
|
|
115
|
+
// callbacks: [callback],// 下载完代码后的回调
|
|
116
|
+
// }
|
|
117
|
+
// }
|
|
118
|
+
const downloadTasksMap = new Map();
|
|
119
|
+
for (const moduleInfo of modules) {
|
|
120
|
+
if (moduleInfo.repoInfo) {
|
|
121
|
+
const { repoInfo: { buildGitTag: branch, httpRepoUrl, path: gitPath = '' }, path, name } = moduleInfo;
|
|
122
|
+
|
|
123
|
+
// 处理仓库权限问题
|
|
124
|
+
const gitUrl = replaceGitUrlAccount(httpRepoUrl, name);
|
|
125
|
+
// 根据gitUrl与branch计算md5
|
|
126
|
+
const md5Key = md5ByGitUrlBranch(gitUrl, branch);
|
|
127
|
+
// git源码临时存在的源目录
|
|
128
|
+
const sourcePath = resolve(sourceDir, md5Key);
|
|
129
|
+
// 模块源码要放到目标目录
|
|
130
|
+
const targetPath = resolve(targetDir, path);
|
|
131
|
+
// 从git源码仓库中找到模块源码路径 (一个仓库存在存放多个模块的情况)
|
|
132
|
+
const sourceModulePath = gitPath ? `${sourcePath}/${gitPath}` : sourcePath;
|
|
133
|
+
|
|
134
|
+
// 下载完代码后,添加回调函数(主要将模块代码从临时目录移动代码到目标目录)
|
|
135
|
+
const callback = {
|
|
136
|
+
params: { sourceModulePath, targetPath },
|
|
137
|
+
fn: async (sourceModulePath, targetPath) => {
|
|
138
|
+
if (fs.existsSync(targetPath)) {
|
|
139
|
+
shelljs.rm('-rf', `${targetPath}/*`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
await moveFile(`${sourceModulePath}`, targetPath, [
|
|
143
|
+
'node_modules',
|
|
144
|
+
'.git',
|
|
145
|
+
]);
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
if (downloadTasksMap.has(sourcePath)) {
|
|
150
|
+
const task = downloadTasksMap.get(sourcePath);
|
|
151
|
+
task.callbacks.push(callback);
|
|
152
|
+
downloadTasksMap.set(sourcePath, task);
|
|
153
|
+
} else {
|
|
154
|
+
let promiseTask;
|
|
155
|
+
if (fs.existsSync(sourcePath) && fs.existsSync(`${sourcePath}/.git`)) {
|
|
156
|
+
promiseTask = (gitUrl, sourcePath, branch, httpRepoUrl) => {
|
|
157
|
+
info(`git pull仓库:${httpRepoUrl}`);
|
|
158
|
+
return pullRepoForGit(sourcePath, branch);
|
|
159
|
+
};
|
|
160
|
+
} else {
|
|
161
|
+
promiseTask = (gitUrl, sourcePath, branch, httpRepoUrl) => {
|
|
162
|
+
info(`git clone仓库: ${httpRepoUrl}`);
|
|
163
|
+
return downloadRepoForGit(gitUrl, sourcePath, branch);
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
downloadTasksMap.set(sourcePath, {
|
|
167
|
+
promiseTask,
|
|
168
|
+
params: {
|
|
169
|
+
gitUrl,
|
|
170
|
+
sourcePath,
|
|
171
|
+
branch,
|
|
172
|
+
httpRepoUrl,
|
|
173
|
+
},
|
|
174
|
+
callbacks: [callback],
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return downloadTasksMap;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* 检查远程模块的gitUrl与 branch是否有更新
|
|
184
|
+
* @param {string} sourceDir 模块源码在缓存区的目录
|
|
185
|
+
* @param {object} moduleInfo 模块的配置信息
|
|
186
|
+
* @returns
|
|
187
|
+
*/
|
|
188
|
+
function checkRemoteModGitUrlBranch(sourceDir, moduleInfo) {
|
|
189
|
+
if (moduleInfo.repoInfo) {
|
|
190
|
+
const { repoInfo: { buildGitTag, httpRepoUrl }, name } = moduleInfo;
|
|
191
|
+
const gitUrl = replaceGitUrlAccount(httpRepoUrl, name);
|
|
192
|
+
const md5Key = md5ByGitUrlBranch(gitUrl, buildGitTag);
|
|
193
|
+
if (!fs.existsSync(`${sourceDir}/${md5Key}`)) {
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
module.exports = {
|
|
201
|
+
cloneModules,
|
|
202
|
+
checkRemoteModGitUrlBranch,
|
|
203
|
+
};
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
const { fail } = require('
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
fail(errMsg);
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
const { fail } = require('../utils/log');
|
|
2
|
+
const { global } = require('../utils/global');
|
|
3
|
+
|
|
4
|
+
function handleError(error) {
|
|
5
|
+
const errMsg = typeof error === 'object' ? error.message : error;
|
|
6
|
+
const isDev = global.getData('isDev');
|
|
7
|
+
if (isDev) {
|
|
8
|
+
fail(errMsg);
|
|
9
|
+
} else {
|
|
10
|
+
fail(errMsg);
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
module.exports = {
|
|
16
|
+
handleError,
|
|
17
|
+
};
|
|
18
|
+
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const { resolve } = require('../utils/widgets');
|
|
3
|
+
const { MODULE_CONFIG_FILENAME, MODULE_CODE_DIR } = require('../config/constant');
|
|
4
|
+
const { checkRemoteModGitUrlBranch } = require('./cloneModules');
|
|
5
|
+
const { checkDependencies } = require('./checkDependencies');
|
|
6
|
+
const { fail } = require('../utils/log');
|
|
7
|
+
|
|
8
|
+
function checkModule(targetModules, contextDir) {
|
|
9
|
+
// 判断\源码\dist\是否存在用户指定的模块
|
|
10
|
+
for (const item of targetModules) {
|
|
11
|
+
// 此模块没有root字段(原因:没有merge到module.config.json的配置项。第三方模块的代码可能还没有下载)
|
|
12
|
+
if (!item.root) {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
// 判断dist目录是否有该模块
|
|
16
|
+
if (!fs.existsSync(`${contextDir}/${item.root}/${MODULE_CONFIG_FILENAME}`)) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// 判断第三方远程模块git地址与branch是否有更新
|
|
21
|
+
if (checkRemoteModGitUrlBranch(MODULE_CODE_DIR, item)) {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// 判断源码目录是否有该模块
|
|
26
|
+
if (item.path && !fs.existsSync(resolve(item.path))) {
|
|
27
|
+
fail(`${item.path}模块代码路径不存在, 请检查tms.config.js的${item.name}模块的path`);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function isInit(tmsConfig, targetModules, contextDir) {
|
|
35
|
+
// 判断是否存在dist目录
|
|
36
|
+
if (!fs.existsSync(contextDir)) {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
// 判断dist是否存在node_modules
|
|
40
|
+
if (!fs.existsSync(`${contextDir}/node_modules`)) {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 判断dist是否存在miniprogram_npm
|
|
45
|
+
if (!fs.existsSync(`${contextDir}/miniprogram_npm`)) {
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// 判断dist是否存在app.json
|
|
50
|
+
if (!fs.existsSync(`${contextDir}/app.json`)) {
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// 判断模块信息
|
|
55
|
+
if (checkModule(targetModules, contextDir)) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 判断package.json的版本是否有新的版本
|
|
60
|
+
if (checkDependencies(targetModules, resolve('./'), tmsConfig.outputDir)) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
module.exports = {
|
|
68
|
+
isInit,
|
|
69
|
+
};
|
|
@@ -1,73 +1,73 @@
|
|
|
1
|
-
const ci = require('miniprogram-ci');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* 获取小程序ci的Project对象
|
|
6
|
-
* @returns {Object} 小程序ci对象
|
|
7
|
-
*/
|
|
8
|
-
const getMpCi = ({ appId, projectPath, type = 'miniProgram', privateKey = 'TODO' }) => {
|
|
9
|
-
const cfgJsonContent = require(path.join(projectPath, 'project.config.json'));
|
|
10
|
-
const ignores = cfgJsonContent?.packOptions?.ignore.map(({ value }) => value) || [];
|
|
11
|
-
|
|
12
|
-
return new ci.Project({
|
|
13
|
-
appid: appId,
|
|
14
|
-
privateKey,
|
|
15
|
-
type,
|
|
16
|
-
projectPath,
|
|
17
|
-
ignores: ['node_modules/**/*', ...ignores],
|
|
18
|
-
});
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
// 用小程序ci工具构建小程序
|
|
23
|
-
const packMpProject = async (project) => {
|
|
24
|
-
await ci.packNpm(project, {
|
|
25
|
-
ignores: ['cloud/**/*'],
|
|
26
|
-
});
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* 格式化构建npm结果信息
|
|
31
|
-
* @param {Array<String>} warning 构建时的告警信息
|
|
32
|
-
* @returns {String} npm构建错误信息
|
|
33
|
-
*/
|
|
34
|
-
const formatPackNpmWarning = (warning) => {
|
|
35
|
-
if (!warning) {
|
|
36
|
-
return '';
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const result = warning.map((it, index) => `${index + 1}. ${it.msg}
|
|
40
|
-
\t@ ${it.jsPath}:${it.tips}`).join('---------------\n');
|
|
41
|
-
|
|
42
|
-
return result;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* 构建miniprogram_npm
|
|
47
|
-
* @returns {Object} 小程序ci对象
|
|
48
|
-
*/
|
|
49
|
-
const buildMpNpm = async ({
|
|
50
|
-
appId,
|
|
51
|
-
projectPath,
|
|
52
|
-
privateKey,
|
|
53
|
-
}) => {
|
|
54
|
-
const mpCi = await getMpCi({
|
|
55
|
-
appId,
|
|
56
|
-
projectPath,
|
|
57
|
-
privateKey,
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
const packNpmWarning = await packMpProject(mpCi);
|
|
61
|
-
|
|
62
|
-
const packNpmMsg = formatPackNpmWarning(packNpmWarning);
|
|
63
|
-
if (packNpmMsg) {
|
|
64
|
-
return Promise.reject(packNpmMsg);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return Promise.resolve();
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
module.exports = {
|
|
72
|
-
buildMpNpm,
|
|
73
|
-
};
|
|
1
|
+
const ci = require('miniprogram-ci');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 获取小程序ci的Project对象
|
|
6
|
+
* @returns {Object} 小程序ci对象
|
|
7
|
+
*/
|
|
8
|
+
const getMpCi = ({ appId, projectPath, type = 'miniProgram', privateKey = 'TODO' }) => {
|
|
9
|
+
const cfgJsonContent = require(path.join(projectPath, 'project.config.json'));
|
|
10
|
+
const ignores = cfgJsonContent?.packOptions?.ignore.map(({ value }) => value) || [];
|
|
11
|
+
|
|
12
|
+
return new ci.Project({
|
|
13
|
+
appid: appId,
|
|
14
|
+
privateKey,
|
|
15
|
+
type,
|
|
16
|
+
projectPath,
|
|
17
|
+
ignores: ['node_modules/**/*', ...ignores],
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
// 用小程序ci工具构建小程序
|
|
23
|
+
const packMpProject = async (project) => {
|
|
24
|
+
await ci.packNpm(project, {
|
|
25
|
+
ignores: ['cloud/**/*'],
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 格式化构建npm结果信息
|
|
31
|
+
* @param {Array<String>} warning 构建时的告警信息
|
|
32
|
+
* @returns {String} npm构建错误信息
|
|
33
|
+
*/
|
|
34
|
+
const formatPackNpmWarning = (warning) => {
|
|
35
|
+
if (!warning) {
|
|
36
|
+
return '';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const result = warning.map((it, index) => `${index + 1}. ${it.msg}
|
|
40
|
+
\t@ ${it.jsPath}:${it.tips}`).join('---------------\n');
|
|
41
|
+
|
|
42
|
+
return result;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 构建miniprogram_npm
|
|
47
|
+
* @returns {Object} 小程序ci对象
|
|
48
|
+
*/
|
|
49
|
+
const buildMpNpm = async ({
|
|
50
|
+
appId,
|
|
51
|
+
projectPath,
|
|
52
|
+
privateKey,
|
|
53
|
+
}) => {
|
|
54
|
+
const mpCi = await getMpCi({
|
|
55
|
+
appId,
|
|
56
|
+
projectPath,
|
|
57
|
+
privateKey,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const packNpmWarning = await packMpProject(mpCi);
|
|
61
|
+
|
|
62
|
+
const packNpmMsg = formatPackNpmWarning(packNpmWarning);
|
|
63
|
+
if (packNpmMsg) {
|
|
64
|
+
return Promise.reject(packNpmMsg);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return Promise.resolve();
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
module.exports = {
|
|
72
|
+
buildMpNpm,
|
|
73
|
+
};
|
package/src/core/npm.js
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 本文件主要负责项目或者分包依赖的npm的安装
|
|
3
|
+
*/
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const fsExtra = require('fs-extra');
|
|
6
|
+
const crypto = require('crypto');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const shell = require('shelljs');
|
|
9
|
+
const glob = require('glob-ignore');
|
|
10
|
+
const log = require('../utils/log');
|
|
11
|
+
const { npmInstall } = require('../utils/widgets');
|
|
12
|
+
const { handleError } = require('./handleError');
|
|
13
|
+
const { info } = require('console');
|
|
14
|
+
|
|
15
|
+
const shellJsOption = { async: false, silent: true };
|
|
16
|
+
const dirPath = process.cwd(); // 项目根目录
|
|
17
|
+
|
|
18
|
+
const collectNpmTasksMap = (packageJsonFiles, cacheDir) => {
|
|
19
|
+
// 下载代码任务 Map (key解释 缓存代码路径/md5(package.json.dependencies)
|
|
20
|
+
// {
|
|
21
|
+
// '/Users/odile/.tmskit/node_modules/026cb72509c2369dbd75779181f820bc': {
|
|
22
|
+
// promiseTask, 下载的任务
|
|
23
|
+
// params: { 下载代码时的参数
|
|
24
|
+
// gitUrl,
|
|
25
|
+
// sourcePath,
|
|
26
|
+
// branch,
|
|
27
|
+
// },
|
|
28
|
+
// callbacks: [callback],// 下载完代码后的回调
|
|
29
|
+
// }
|
|
30
|
+
// }
|
|
31
|
+
const npmTasksMap = new Map();
|
|
32
|
+
for (const packageJsonPath of packageJsonFiles) {
|
|
33
|
+
const packageContent = fs.readFileSync(packageJsonPath);
|
|
34
|
+
const packageJson = JSON.parse(packageContent);
|
|
35
|
+
const md5Obj = {
|
|
36
|
+
dependencies: packageJson.dependencies || {},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
if (Object.keys(md5Obj.dependencies).length !== 0) {
|
|
40
|
+
const md5Key = crypto.createHash('md5').update(JSON.stringify(md5Obj))
|
|
41
|
+
.digest('hex');
|
|
42
|
+
const cacheNMPath = path.join(cacheDir, md5Key);
|
|
43
|
+
const cacheNMTarFile = path.join(cacheNMPath, 'node_modules.tar.gz');
|
|
44
|
+
|
|
45
|
+
// 下载后,添加回调函数 (拷贝node_modules.tar.gz到编译目录并解压)
|
|
46
|
+
const callback = {
|
|
47
|
+
params: { cacheNMPath, cacheNMTarFile, packageJsonDir: path.dirname(packageJsonPath), shell },
|
|
48
|
+
fn: async (cacheNMPath, cacheNMTarFile, packageJsonDir, shell) => {
|
|
49
|
+
shell.cd(cacheNMPath);
|
|
50
|
+
shell.cp('-Rf', cacheNMTarFile, `${packageJsonDir}/`);
|
|
51
|
+
const newShellJsOption = {
|
|
52
|
+
...shellJsOption,
|
|
53
|
+
cwd: packageJsonDir,
|
|
54
|
+
};
|
|
55
|
+
shell.exec('tar -xzvf ./node_modules.tar.gz -C ./', newShellJsOption);
|
|
56
|
+
shell.exec('rm -rf ./node_modules.tar.gz', newShellJsOption);
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
if (npmTasksMap.has(cacheNMPath)) {
|
|
61
|
+
const task = npmTasksMap.get(cacheNMPath);
|
|
62
|
+
task.callbacks.push(callback);
|
|
63
|
+
npmTasksMap.set(cacheNMPath, task);
|
|
64
|
+
} else {
|
|
65
|
+
const missCache = !fsExtra.pathExistsSync(cacheNMPath)
|
|
66
|
+
|| !fsExtra.existsSync(cacheNMTarFile)
|
|
67
|
+
|| fsExtra.statSync(cacheNMTarFile).size < 512;
|
|
68
|
+
let promiseTask = () => Promise.resolve();
|
|
69
|
+
if (missCache) {
|
|
70
|
+
promiseTask = (packageJsonPath, cacheNMPath, shell) => {
|
|
71
|
+
fsExtra.emptydirSync(cacheNMPath);
|
|
72
|
+
shell.cp('-f', packageJsonPath, cacheNMPath);
|
|
73
|
+
info(`npm install: ${packageJsonPath}`);
|
|
74
|
+
return npmInstall(cacheNMPath).then(() => {
|
|
75
|
+
const newShellJsOption = {
|
|
76
|
+
...shellJsOption,
|
|
77
|
+
cwd: cacheNMPath,
|
|
78
|
+
};
|
|
79
|
+
shell.exec('tar -zcvf ./node_modules.tar.gz ./node_modules', newShellJsOption);
|
|
80
|
+
shell.exec('rm -rf ./node_modules', newShellJsOption);
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
npmTasksMap.set(cacheNMPath, {
|
|
85
|
+
promiseTask,
|
|
86
|
+
params: {
|
|
87
|
+
packageJsonPath,
|
|
88
|
+
cacheNMPath,
|
|
89
|
+
shell,
|
|
90
|
+
},
|
|
91
|
+
callbacks: [callback],
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return npmTasksMap;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
// 遍历安装指定目录下所有项目的npm依赖
|
|
101
|
+
const mpNpmInstallAll = async (modules, contextDir, cacheDir) => {
|
|
102
|
+
const packageJsonFiles = await findAllPackageJson(modules, contextDir);
|
|
103
|
+
|
|
104
|
+
// 收集npm install的任务
|
|
105
|
+
const npmTasksMap = collectNpmTasksMap(packageJsonFiles, cacheDir);
|
|
106
|
+
|
|
107
|
+
// 开始执行npm install和回调(移动)的任务
|
|
108
|
+
const arrPromises = [];
|
|
109
|
+
npmTasksMap.forEach(({ promiseTask, params, callbacks }) => {
|
|
110
|
+
arrPromises.push(promiseTask(...Object.keys(params).map(key => params[key]))
|
|
111
|
+
.then(async () => {
|
|
112
|
+
const callArr = callbacks.map(async ({
|
|
113
|
+
params: cParams,
|
|
114
|
+
fn,
|
|
115
|
+
}) => fn(...Object.keys(cParams).map(key => cParams[key])));
|
|
116
|
+
return Promise.all(callArr);
|
|
117
|
+
})
|
|
118
|
+
.catch((e) => {
|
|
119
|
+
handleError(`npm install ${params.packageJsonPath}出现错误:${e}`);
|
|
120
|
+
}));
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
await Promise.all(arrPromises);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* 递归查找指定条件的文件
|
|
128
|
+
* @param {String} startPath 开始查找的根路径
|
|
129
|
+
* @param {String} filter 匹配的字符串
|
|
130
|
+
* @returns {Array<String>} 查找到的文件路径列表
|
|
131
|
+
*/
|
|
132
|
+
const findFilesByFilter = (startPath, filter) => {
|
|
133
|
+
const result = [];
|
|
134
|
+
/**
|
|
135
|
+
* 根据指定的筛选器查找文件
|
|
136
|
+
* @param {String} startPath 开始查找的文件夹路径
|
|
137
|
+
* @param {String} filter 筛选器
|
|
138
|
+
* @returns {Undefined} 无需返回值
|
|
139
|
+
*/
|
|
140
|
+
const find = (startPath, filter) => {
|
|
141
|
+
// 目录不存在
|
|
142
|
+
if (!fs.existsSync(startPath)) {
|
|
143
|
+
log.fail(`${startPath}目录不存在`);
|
|
144
|
+
process.exit(-1);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// 当前目录下的所有文件 / 文件夹
|
|
149
|
+
const exceptDir = ['node_modules', 'miniprogram_npm'];
|
|
150
|
+
if (exceptDir.find(item => startPath.indexOf(item) > -1)) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const files = fs.readdirSync(startPath);
|
|
154
|
+
files.forEach((file) => {
|
|
155
|
+
const filename = path.join(startPath, file);
|
|
156
|
+
const stat = fs.lstatSync(filename);
|
|
157
|
+
// 当前文件是文件夹类型,继续递归
|
|
158
|
+
if (stat.isDirectory()) {
|
|
159
|
+
find(filename, filter);
|
|
160
|
+
} else if (filename.indexOf(filter) >= 0) {
|
|
161
|
+
// 文件类型
|
|
162
|
+
result.push(filename);
|
|
163
|
+
};
|
|
164
|
+
});
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
find(startPath, filter);
|
|
168
|
+
return result;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* 找到项目中所有的package.json文件
|
|
173
|
+
* @param {Array<String>} subRoots 需要安装npm依赖的路径
|
|
174
|
+
* @param {String} contextDir 命令运行的目录
|
|
175
|
+
* @returns {Array<String>} 找到的所有package.json文件的路径
|
|
176
|
+
*/
|
|
177
|
+
const findAllPackageJson = (subRoots = [], contextDir) => {
|
|
178
|
+
const packageJsonName = 'package.json'; // 查找文件名
|
|
179
|
+
const cwd = contextDir || dirPath;
|
|
180
|
+
const result = [path.join(cwd, packageJsonName)]; // 默认填充根目录下的package.json
|
|
181
|
+
|
|
182
|
+
subRoots.forEach((subRoot) => {
|
|
183
|
+
if (!subRoot.root) {
|
|
184
|
+
log.fail(`请检查${subRoot.name}的module.config.json是否有root字段`);
|
|
185
|
+
process.exit(1);
|
|
186
|
+
}
|
|
187
|
+
const toppath = path.join(cwd, subRoot.root); // 从该目录开始查找package.json文件
|
|
188
|
+
const list = findFilesByFilter(toppath, packageJsonName);
|
|
189
|
+
|
|
190
|
+
result.push(...list);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
return result;
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
function cloudNpmInstall(contextDir) {
|
|
197
|
+
return new Promise((resolve, reject) => {
|
|
198
|
+
glob(`${contextDir}/**/package.json`, ['node_modules', 'miniprogram_npm'], (err, files) => {
|
|
199
|
+
if (err) {
|
|
200
|
+
reject(err);
|
|
201
|
+
}
|
|
202
|
+
files.forEach((file) => {
|
|
203
|
+
const dir = path.dirname(file);
|
|
204
|
+
shell.cd(dir);
|
|
205
|
+
shell.exec('npx npm install --production --registry http://mirrors.tencent.com/npm/', { silent: false });
|
|
206
|
+
});
|
|
207
|
+
resolve();
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
module.exports = {
|
|
214
|
+
cloudNpmInstall,
|
|
215
|
+
mpNpmInstallAll,
|
|
216
|
+
findAllPackageJson,
|
|
217
|
+
};
|
|
218
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const { resolve } = require('../utils/widgets');
|
|
3
|
+
const { handleError } = require('./handleError');
|
|
4
|
+
const { DEFAULT_CLOUD_MODULE_DIR } = require('../config/constant');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 根据相关配置创建软链接
|
|
8
|
+
* @param { object } tmsConfig
|
|
9
|
+
*/
|
|
10
|
+
const symLink = (tmsConfig) => {
|
|
11
|
+
try {
|
|
12
|
+
if (tmsConfig.cloudModules) {
|
|
13
|
+
tmsConfig.cloudModules.forEach((item) => {
|
|
14
|
+
fs.symlinkSync(resolve(item.path), resolve(DEFAULT_CLOUD_MODULE_DIR, item.name));
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
} catch (e) {
|
|
18
|
+
handleError(`创建软链错误: ${e}`);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
module.exports = {
|
|
23
|
+
symLink,
|
|
24
|
+
};
|