作用:当前项目中的 node_modules 中存在一个脚手架命令,和全局的 node 环境中也存在一个脚手架命令的时候,它会优先选用 node_modules 中的本地版本。
通常情况,全局安装一个脚手架后,本地是不需要安装脚手架的。但是当我们本地安装脚手架的时候,意味着我们项目里用到了这个脚手架。当与全局冲突的时候,比如全局和本地都有这个脚手架,但是版本不同,那么我们应该使用本地的脚手架。这就是import-local的作用。
1、源码
#!/usr/bin/env node"use strict";/* eslint-disable import/no-dynamic-require, global-require */const importLocal = require("import-local");//__filename 表示当前的文件路径 为true 则用输出使用本地版本的log//判断本地`node_modules` 中是否存在脚手架if (importLocal(__filename)) {require("npmlog").info("cli", "using local version of lerna");} else {//这个模块返回了一个 main 方法 并把 process.argv.slice(2) 作为参数执行require(".")(process.argv.slice(2));}
'use strict';const path = require('path');const {fileURLToPath} = require('url');const resolveCwd = require('resolve-cwd');const pkgDir = require('pkg-dir');module.exports = filename => {//得到文件具体路径const normalizedFilename = filename.startsWith('file://') ? fileURLToPath(filename) : filename;//获取当前脚手架所在的全局目录,包括package.json目录 返回 path 的目录名//path.dirname 去掉文件名,返回目录 //globalDir 全局的路径 cwd当前node命令执行时所在的文件夹目录const globalDir = pkgDir.sync(path.dirname(normalizedFilename));//将 globalDir 和 filename 进行相对路径比较 ,得到当前文件名//path.relative 根据当前工作目录返回从 from 到 to 的相对路径,相同返回''const relativePath = path.relative(globalDir, normalizedFilename);// 将 globalDir 和 package.json 的路径进行合并,得到package.json的信息const pkg = require(path.join(globalDir, 'package.json'));//将 pkg.name 和 relativePath 进行了合并 得到lerna/cli.jsconst _r=path.join(pkg.name, relativePath)// 判断当前本地是否有这个文件,有则返回路径const localFile = resolveCwd.silent(_r);//得到本地的node_modulesconst localNodeModules = path.join(process.cwd(), 'node_modules');const _l= path.relative(localNodeModules, normalizedFilename)// //返回的对象方法会返回一个对象,其属性表示 path 的有效元素,属性包括dir、root、base、name、extconst _lr=path.parse(localNodeModules).rootconst _nr=path.parse(normalizedFilename).rootconst filenameInLocalNodeModules = !_l.startsWith('..') &&_lr === _nr;const _ln= path.relative(localFile, normalizedFilename)const flag=!filenameInLocalNodeModules && localFile && _ln !== ''return flag && require(localFile);};
本项目中的结果:
全局安装的结果(全局安装后 会先加载进入全局的import-lacal,在进入core/cli界面,【暂不清楚原因】)
返回true,执行log运行后执行微任务,打印其他信息
2、结论
import-local 模块就是一个函数,当条件满足的时候,会先执行函数内部的 require(localFile).
那为什么 using local version of lerna 会在最前面打印出来呢?
脚手架 command 内部的实现是利用了微任务队列,虽然先执行了 require(localFile),但是真正的执行逻辑都放在微任务队列里了,而 using local version of lerna 是宏任务最后的内容,所以会在执行宏任务的时候输出 log,然后再执行微任务队列里脚手架实际的业务逻辑代码。
