我知道,听起来很简单。但请继续阅读以了解我面临的挑战。
我正在尝试创建一个'init'命令,以帮助建立用于开发的克隆存储库。我们利用远程程序包管理器,要求开发人员在处理程序包时在存储库中有一个.npmrc
文件(我们不想通过使用全局.npmrc
文件来限制用户)。该过程应如下所示:
.npmrc
文件写入其系统npm i
npm run build
我在script
中创建了一个新的package.json
:
"init": "node ./scripts/writeNpmRc.js && npm i && npm run build && node ./scripts/init.js"
我的writeNpmRc.js
文件使用readline
来获取用户输入,然后写入该文件(请记住,此时我们尚未运行npm i
,因此我们正在处理按节点安装的内容)。
const readline = require('readline');
const fs = require('fs');
const path = require('path');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const writeFile = function(dest, data) {
return new Promise((resolve, reject) => {
fs.writeFile(dest, data, 'utf-8', function(err) {
if (err) {
reject(err);
}
resolve();
});
});
};
const getUsername = () => {
const promise = new Promise((resolve, reject) => {
try {
rl.question(
'What is your username (typically firstname.lastname)? ',
result => {
if (!result) {
console.error('You must provide your username.');
return getUsername();
}
resolve(result);
}
);
} catch (err) {
reject(err);
}
});
return promise
.catch(err => {
console.error('[getUsername] ', err);
})
.finally(() => {
rl.close();
});
};
(async () => {
const userName = await getUsername();
const fileData = `registry=http://my.remote.repo/url/
email=${userName}@email.com`;
await writeFile(path.resolve(__dirname, '../.npmrc'), fileData).catch(err => {
console.err('[writeFile Error]', err);
});
console.log('[END writeNpmRcFile]');
process.exit(0);
})();
该部分似乎运行正常,但后续命令(npm i
)不使用新的.npmrc
文件和安装炸弹。我可以(在失败之后)运行npm i
很好,因此文件内容本身似乎是正确的。实际上,如果我手动放置.npmrc
文件并运行所有内容,except writeNpmRcFile.js
,它就可以正常运行。只有当我链接此命令时,它们才会失败。
我知道我想念什么,我只是不知道什么?我等待fs.writeFile
成功完成(可能只需要使用writeFileSync
...)。就像文件系统没有及时释放下一个命令的.npmrc
文件。我什至在某一时刻设置了一个自定义的异步wait()
方法,该方法在退出该过程之前会暂停一秒钟,但这没有帮助。有什么想法吗?
因此,@ RobC在他的评论中很有道理,在编写了child_process
文件之后,我测试了有关使用npm i
运行.npmrc
步骤的后续理论。测试表明,我认为正确,它在单独的上下文中运行了该命令,并且该上下文将使用新文件。对于那些好奇的人,这里是我更新的writeNpmRcFile.js
,其中包括安装。
const readline = require('readline');
const fs = require('fs');
const path = require('path');
const { exec } = require('child_process');
let rl;
let spinnerInterval;
const getInterface = () =>
readline.createInterface({
input: process.stdin,
output: process.stdout
});
const writeFile = function(dest, data) {
return new Promise((resolve, reject) => {
fs.writeFile(dest, data, 'utf-8', function(err) {
if (err) {
reject(err);
}
resolve();
});
});
};
const runInstall = () => {
console.log('Running npm install (This may take a few, so be patient)');
spinnerInterval = twirlTimer();
const promise = new Promise((resolve, reject) => {
exec(
'npm i',
{ cwd: path.resolve(__dirname, '../') },
(err, stdout, stderr) => {
clearInterval(spinnerInterval);
if (err) {
reject(err);
}
console.log(`stdout: ${stdout}`);
console.error(`stderr: ${stderr}`);
resolve();
}
);
});
return promise.catch(err => {
clearInterval(spinnerInterval));
return Promise.reject(err);
}
};
const twirlTimer = function() {
var P = ['\\', '|', '/', '-'];
var x = 0;
return setInterval(function() {
process.stdout.write('\r' + P[x++]);
x &= 3;
}, 250);
};
const getUsername = () => {
if (!rl) rl = getInterface();
const promise = new Promise((resolve, reject) => {
try {
rl.question(
'What is your username (typically firstname.lastname)? ',
result => {
if (!result) {
console.error('You must provide your username.');
return getUsername();
}
resolve(result);
}
);
} catch (err) {
reject(err);
}
});
return promise
.catch(err => {
console.error('[getUsername] ', err);
})
.finally(() => {
rl.close();
});
};
(async () => {
const userName = await getUsername();
// prettier-ignore
const fileData = `registry=http://my.remote.repo/url/
email=${userName}@email.com`;
console.log(`Writing your '.npmrc' file to the directory`);
await writeFile(path.resolve(__dirname, '../.npmrc'), fileData).catch(err => {
console.error('[writeFile Error] ', err);
});
await runInstall().catch(err => {
console.log('[runInstall Error] ', err);
});
console.log('[END writeNpmRcFile]');
process.exit(0);
})();
进行了此更改后,我的package.json
scripts
对此进行了更改:
"scripts": {
"lint": "eslint ./scripts",
"start": "node ./dist/index.js",
"release": "standard-version",
"write-npmrc": "node ./scripts/writeNpmRcFile.js",
"init": "npm run write-npmrc && npm run build && node ./scripts/init.js",
"build": "node ./scripts/build.js"
}