最新消息:20210816 当前crifan.com域名已被污染,为防止失联,请关注(页面右下角的)公众号

【记录】研究搞懂gitbook内部调用npm去install插件的逻辑和相关代码

插件 crifan 770浏览 0评论
折腾:
【未解决】给gitbook install的npm添加代理无效
期间,去研究
git install
输出的log
[email protected]  ~/dev/crifan/gitbook/gitbook_template/books/gitbook_demo   master ●  gitbook install
info: installing 18 plugins using [email protected]
info:
info: installing plugin "google-adsense"
info: install plugin "google-adsense" (*) from NPM with version 0.1.0
另外,从报错中:
   at ReadStream.Readable.on (_stream_readable.js:849:29)
    at untarStream (/Users/xxx/.gitbook/versions/3.2.3/node_modules/npm/lib/fetch-package-metadata.js:304:8)
    at addShrinkwrap (/Users/xxx/.gitbook/versions/3.2.3/node_modules/npm/lib/fetch-package-metadata.js:200:3)
    at /Users/xxx/.gitbook/versions/3.2.3/node_modules/npm/lib/fetch-package-metadata.js:185:14
    at /Users/xxx/.gitbook/versions/3.2.3/node_modules/npm/node_modules/iferr/index.js:13:50
    at RES (/Users/xxx/.gitbook/versions/3.2.3/node_modules/npm/node_modules/inflight/inflight.js:23:14)
    at f (/Users/xxx/.gitbook/versions/3.2.3/node_modules/npm/node_modules/once/once.js:17:25)
    at /Users/xxx/.gitbook/versions/3.2.3/node_modules/npm/lib/cache.js:362:16
    at /Users/xxx/.gitbook/versions/3.2.3/node_modules/npm/node_modules/write-file-atomic/index.js:29:9
    at LOOP (/Users/xxx/.gitbook/versions/3.2.3/node_modules/npm/node_modules/slide/lib/chain.js:7:26)
可以看出:
内部调用到了:
/Users/xxx/.gitbook/versions/3.2.3
下面的npm
node_modules/npm
想要搞清楚内部npm内部如何用上代理。
/Users/xxx/.gitbook/versions/3.2.3/package.json
{
  "name": "gitbook",
  "version": "3.2.3",
  "homepage": "https://www.gitbook.com",
  "description": "Library and cmd utility to generate GitBooks",
其中的:
3.2.3是gitbook的版本
搜:
install
找到了:
/Users/xxx/.gitbook/versions/3.2.3/lib/cli/index.js
var buildEbook = require('./buildEbook');


module.exports = [
    require('./build'),
    require('./serve'),
    require('./install'),
    require('./parse'),
    require('./init'),
    buildEbook('pdf'),
    buildEbook('epub'),
    buildEbook('mobi')
];
除了install
还要很多,比如pdf/epub/mobi等格式,和之前的build/serve/init等命令
引用的是
/Users/xxx/.gitbook/versions/3.2.3/lib/cli/install.js
var options = require('./options');
var getBook = require('./getBook');


var Parse = require('../parse');
var Plugins = require('../plugins');


module.exports = {
    name: 'install [book]',
    description: 'install all plugins dependencies',
    options: [
        options.log
    ],
    exec: function(args, kwargs) {
        var book = getBook(args, kwargs);


        return Parse.parseConfig(book)
        .then(function(resultBook) {
            return Plugins.installPlugins(resultBook);
        });
    }
};
此处引用的是:
Plugins.installPlugins
通过加了:
console.info("book=%o", book)
调试打印出:
  gitbook install
book=Record { "logger": [object Object], "fs": Record { "root": "/Users/xxx/dev/crifan/gitbook/gitbook_template/books/gitbook_demo", "fsExists": function fileExists(filename) {
    var d = Promise.defer();


    fs.exists(filename, function(exists) {
        d.resolve(exists);
    });


    return d.promise;
}, "fsReadFile": function () {
        var nodeArgs = baseArgs.concat(array_slice(arguments));
        var deferred = defer();
        nodeArgs.push(deferred.makeNodeResolver());
        Q(callback).fapply(nodeArgs).fail(deferred.reject);
        return deferred.promise;
    }, "fsStatFile": function () {
        var nodeArgs = baseArgs.concat(array_slice(arguments));
        var deferred = defer();
        nodeArgs.push(deferred.makeNodeResolver());
        Q(callback).fapply(nodeArgs).fail(deferred.reject);
        return deferred.promise;
    }, "fsReadDir": function fsReadDir(folder) {
    return fs.readdir(folder)
    .then(function(files) {
        files = Immutable.List(files);


        return files
            .map(function(file) {
                if (file == '.' || file == '..') return;


                var stat = fs.statSync(path.join(folder, file));
                if (stat.isDirectory()) file = file + path.sep;
                return file;
            })
            .filter(function(file) {
                return Boolean(file);
            });
    });
}, "fsLoadObject": function fsLoadObject(filename) {
    return fresh(filename, require);
}, "fsReadAsStream": function createReadStream (path, options) {
    return new ReadStream(path, options)
  } }, "ignore": Ignore { "ignore": [object Object] }, "config": Config { "file": Record { "path": "", "mtime": "Wed Jan 20 2021 21:04:04 GMT+0800 (中国标准时间)" }, "values": Map { "gitbook": "*", "theme": "default", "variables": Map {}, "plugins": List [], "pluginsConfig": Map {}, "structure": Map { "langs": "LANGS.md", "readme": "README.md", "glossary": "GLOSSARY.md", "summary": "SUMMARY.md" }, "pdf": Map { "pageNumbers": true, "fontSize": 12, "fontFamily": "Arial", "paperSize": "a4", "chapterMark": "pagebreak", "pageBreaksBefore": "/", "margin": Map { "right": 62, "left": 62, "top": 56, "bottom": 56 } } } }, "readme": Record { "file": Record { "path": "", "mtime": "Wed Jan 20 2021 21:04:04 GMT+0800 (中国标准时间)" }, "title": "", "description": "" }, "summary": Summary { "file": Record { "path": "", "mtime": "Wed Jan 20 2021 21:04:04 GMT+0800 (中国标准时间)" }, "parts": List [] }, "glossary": Record { "file": Record { "path": "", "mtime": "Wed Jan 20 2021 21:04:04 GMT+0800 (中国标准时间)" }, "entries": OrderedMap {} }, "languages": Record { "file": Record { "path": "", "mtime": "Wed Jan 20 2021 21:04:04 GMT+0800 (中国标准时间)" }, "list": OrderedMap {} }, "language": "", "books": OrderedMap {} }
(node:1340) [DEP0079] DeprecationWarning: Custom inspection function on Objects via .inspect() is deprecated
。。。
另外:
console.info("resultBook=%o", resultBook)
输出类似。
/Users/xxx/.gitbook/versions/3.2.3/lib/plugins/installPlugins.js
var npmi = require('npmi');


var DEFAULT_PLUGINS = require('../constants/defaultPlugins');
var Promise = require('../utils/promise');
var installPlugin = require('./installPlugin');


/**
    Install plugin requirements for a book


    @param {Book}
    @return {Promise<Number>}
*/
function installPlugins(book) {
    var logger = book.getLogger();
    var config = book.getConfig();
    var plugins = config.getPluginDependencies();


    // Remove default plugins
    // (only if version is same as installed)
    plugins = plugins.filterNot(function(plugin) {
        var dependency = DEFAULT_PLUGINS.find(function(dep) {
            return dep.getName() === plugin.getName();
        });


        return (
            // Disabled plugin
            !plugin.isEnabled() ||


            // Or default one installed in GitBook itself
            (dependency &&
            plugin.getVersion() === dependency.getVersion())
        );
    });


    if (plugins.size == 0) {
        logger.info.ln('nothing to install!');
        return Promise();
    }


    logger.info.ln('installing', plugins.size, 'plugins using [email protected]' + npmi.NPM_VERSION);


    return Promise.forEach(plugins, function(plugin) {
        return installPlugin(book, plugin);
    })
    .thenResolve(plugins.size);
}


module.exports = installPlugins;
去打印:
console.info("config=%o", config)
出:
config=Config { "file": Record { "path": "book.json", "mtime": Wed Jan 20 2021 16:47:19 GMT+0800 (中国标准时间) }, "values": Map { "plugins": List [ "google-adsense", "theme-comscore", "anchors", "-lunr", "-search", "search-plus", "disqus", "-highlight", "prism", "prism-themes", "github-buttons", "splitter", "-sharing", "sharing-plus", "tbfed-pagefooter", "expandable-chapters-small", "ga", "donate", "sitemap-general", "copy-code-button", "callouts", "toolbar-button" ], "root": "./src", "pluginsConfig": Map { "tbfed-pagefooter": Map { "copyright": "crifan.com,使用<a href='https://creativecommons.org/licenses/by/4.0/deed.zh'>署名4.0国际(CC BY 4.0)协议</a>发布", "modify_label": "最后更新:", "modify_format": "YYYY-MM-DD HH:mm:ss" }, "prism": Map { "css": List [ "prism-themes/themes/prism-atom-dark.css" ] }, "disqus": Map { "shortName": "crifan" }, "callouts": Map { "showTypeInHeader": false }, "toolbar-button": Map { "url": "http://book.crifan.com/books/gitbook_demo/pdf/gitbook_demo.pdf", "icon": "fa-file-pdf-o", "label": "下载PDF" }, "autocover": Map { "title": "Gitbook演示", "author": "Crifan Li <xxx>", "font": Map { "size": null, "family": "Impact", "color": "#FFF" }, "size": Map { "w": 1800, "h": 2360 }, "background": Map { "color": "#09F" } }, "donate": Map { "wechat": "https://www.crifan.com/files/res/crifan_com/crifan_wechat_pay.jpg", "alipay": "https://www.crifan.com/files/res/crifan_com/crifan_alipay_pay.jpg", "title": "", "button": "打赏", "alipayText": "支付宝打赏给Crifan", "wechatText": "微信打赏给Crifan" }, "sitemap-general": Map { "prefix": "https://book.crifan.com/gitbook/gitbook_demo/website/" }, "google-adsense": Map { "ads": List [ Map { "client": "ca-pub-6626240105039250" } ] }, "github-buttons": Map { "buttons": List [ Map { "repo": "gitbook_demo", "user": "crifan", "type": "star", "count": true, "size": "small" }, Map { "user": "crifan", "type": "follow", "width": "120", "count": false, "size": "small" } ] }, "ga": Map { "token": "UA-28297199-1" }, "sharing": Map { "qq": true, "all": List [ "douban", "facebook", "google", "instapaper", "line", "linkedin", "messenger", "pocket", "qq", "qzone", "stumbleupon", "twitter", "viber", "vk", "weibo", "whatsapp" ], "douban": false, "facebook": true, "weibo": true, "instapaper": false, "whatsapp": false, "hatenaBookmark": false, "twitter": true, "messenger": false, "line": false, "vk": false, "pocket": false, "google": false, "viber": false, "stumbleupon": false, "qzone": false, "linkedin": false }, "theme-default": Map { "showLevel": true } }, "theme": "default", "author": "Crifan Li <xxx>", "pdf": Map { "pageNumbers": true, "fontSize": 12, "fontFamily": "Arial", "paperSize": "a4", "chapterMark": "pagebreak", "pageBreaksBefore": "/", "margin": Map { "right": 62, "left": 62, "top": 56, "bottom": 56 } }, "structure": Map { "langs": "LANGS.md", "readme": "README.md", "glossary": "GLOSSARY.md", "summary": "SUMMARY.md" }, "variables": Map {}, "title": "Gitbook演示", "language": "zh-hans", "links": Map { "sidebar": Map { "主页": "https://www.crifan.com" } }, "gitbook": "3.2.3", "description": "crifan的Gitbook模版,用于演示如何用Gitbook创建一个自己的book电子书" } }
就是我们的gitbook_demo的配置
console.info("plugins=%o", plugins)
输出:
plugins=List [ PluginDependency { "name": "google-adsense", "version": "*", "enabled": true }, PluginDependency { "name": "theme-comscore", "version": "*", "enabled": true }, PluginDependency { "name": "anchors", "version": "*", "enabled": true }, PluginDependency { "name": "search-plus", "version": "*", "enabled": true }, PluginDependency { "name": "disqus", "version": "*", "enabled": true }, PluginDependency { "name": "prism", "version": "*", "enabled": true }, PluginDependency { "name": "prism-themes", "version": "*", "enabled": true }, PluginDependency { "name": "github-buttons", "version": "*", "enabled": true }, PluginDependency { "name": "splitter", "version": "*", "enabled": true }, PluginDependency { "name": "sharing-plus", "version": "*", "enabled": true }, PluginDependency { "name": "tbfed-pagefooter", "version": "*", "enabled": true }, PluginDependency { "name": "expandable-chapters-small", "version": "*", "enabled": true }, PluginDependency { "name": "ga", "version": "*", "enabled": true }, PluginDependency { "name": "donate", "version": "*", "enabled": true }, PluginDependency { "name": "sitemap-general", "version": "*", "enabled": true }, PluginDependency { "name": "copy-code-button", "version": "*", "enabled": true }, PluginDependency { "name": "callouts", "version": "*", "enabled": true }, PluginDependency { "name": "toolbar-button", "version": "*", "enabled": true } ]
是此处的插件列表
继续:
/Users/xxx/.gitbook/versions/3.2.3/lib/plugins/installPlugin.js
var npmi = require('npmi');


var Promise = require('../utils/promise');
var resolveVersion = require('./resolveVersion');


/**
    Install a plugin for a book


    @param {Book}
    @param {PluginDependency}
    @return {Promise}
*/
function installPlugin(book, plugin) {
    var logger = book.getLogger();


    var installFolder = book.getRoot();
    var name = plugin.getName();
    var requirement = plugin.getVersion();


    logger.info.ln('');
    logger.info.ln('installing plugin "' + name + '"');


    // Find a version to install
    return resolveVersion(plugin)
    .then(function(version) {
        if (!version) {
            throw new Error('Found no satisfactory version for plugin "' + name + '" with requirement "' + requirement + '"');
        }


        logger.info.ln('install plugin "' + name +'" (' + requirement + ') from NPM with version', version);
        return Promise.nfcall(npmi, {
            'name': plugin.getNpmID(),
            'version': version,
            'path': installFolder,
            'npmLoad': {
                'loglevel': 'silent',
                'loaded': true,
                'prefix': installFolder
            }
        });
    })
    .then(function() {
        logger.info.ok('plugin "' + name + '" installed with success');
    });
}


module.exports = installPlugin;
貌似核心的是:
return Promise.nfcall(npmi, {
看到函数原型是:
/Users/xxx/Library/Caches/typescript/4.1/node_modules/@types/q/index.d.ts
    /**
     * Calls a Node.js-style function with the given variadic arguments, returning a promise that is fulfilled if the
     * Node.js function calls back with a result, or rejected if it calls back with an error
     * (or throws one synchronously). An example:
     *
     * @example
     * Q.nfcall(FS.readFile, "foo.txt", "utf-8").done(function (text) {
     * });
     *
     * The same warning about functions vs. methods applies for nfcall as it does for nfapply. In this case, the better
     * strategy would be to use Q.ninvoke.
     */
    export function nfcall<T>(nodeFunction: (...args: any[]) => any, ...args: any[]): Promise<T>;
此处:
  • nodeFunction=npmi
  • args = 此处json=dict
{
            'name': plugin.getNpmID(),
            'version': version,
            'path': installFolder,
            'npmLoad': {
                'loglevel': 'silent',
                'loaded': true,
                'prefix': installFolder
            }
/Users/xxx/.gitbook/versions/3.2.3/node_modules/npmi/npmi.js
var npm    = require('npm');
var fs     = require('fs');
var path   = require('path');
var semver = require('semver');


var LOAD_ERR    = 'NPM_LOAD_ERR',
    INSTALL_ERR = 'NPM_INSTALL_ERR',
    VIEW_ERR    = 'NPM_VIEW_ERR';


/**
 * Created with IntelliJ IDEA.
 * User: leiko
 * Date: 30/01/14
 * Time: 10:28
 */
var npmi = function (options, callback) {
    callback = callback || function () {};


    var name         = options.name,
        pkgName      = options.pkgName || name,
        version      = options.version || 'latest',
        installPath  = options.path || '.',
        forceInstall = options.forceInstall || false,
        localInstall = options.localInstall || false,
        npmLoad      = options.npmLoad || {loglevel: 'silent'},
        savedPrefix  = null;

    function viewCallback(installedVersion)  {

。。。
    function checkInstalled(isTarball) {

。。。
    function installCallback(err, result) {
        // reset npm.prefix to saved value
        npm.prefix = savedPrefix;


        if (err) {
            err.code = INSTALL_ERR;
        }


        callback(err, result);
    }

。。。
    function loadCallback(err) {
。。。
npmi.LOAD_ERR    = LOAD_ERR;
npmi.INSTALL_ERR = INSTALL_ERR;
npmi.VIEW_ERR    = VIEW_ERR;


npmi.NPM_VERSION = npm.version;


module.exports = npmi;
感觉是:
此处报错就是调用了installCallback,发生了error
试试:
        // callback(err, result);
        console.info("err=%o", err)
        console.info("result=%o", result)
输出:
好像没有多余输出。
另外去看:
loadCallback
        console.info("loadCallback:err=%o", err)
没有
        console.info("checkInstalled: isTarball=%o", isTarball)
结果:
没有
    function viewCallback(installedVersion)  {
        console.info("viewCallback: installedVersion=%o", installedVersion)
也没有。
var npmi = function (options, callback) {
    console.info("npmi: options=%o", options)
结果:也没有。
看来不是这个文件。
console.info("in npmi")
有输出,确定是加载了:
/Users/xxx/.gitbook/versions/3.2.3/node_modules/npmi/npmi.js
搜npmi
找到
/Users/xxx/.gitbook/versions/3.2.3/package.json
    "npm": "3.9.2",
    "npmi": "2.0.1",
    console.info("npmLoad=%o", npmLoad)
    console.info("loadCallback=%o", loadCallback)
    npm.load(npmLoad, loadCallback);
结果:没有
/Users/xxx/.gitbook/versions/3.2.3/node_modules/npm/package.json
  "bin": {
    "npm": "./bin/npm-cli.js"
  },
去看看
/Users/xxx/.gitbook/versions/3.2.3/node_modules/npm/bin/npm-cli.js
#!/usr/bin/env node
;(function () { // wrapper in case we're in module_context mode
  // windows: running "npm blah" in this folder will invoke WSH, not node.
  /*global WScript*/
  if (typeof WScript !== 'undefined') {
    WScript.echo(
      'npm does not work when run\n' +
        'with the Windows Scripting Host\n\n' +
        "'cd' to a different directory,\n" +
        "or type 'npm.cmd <args>',\n" +
        "or type 'node npm <args>'."
    )
    WScript.quit(1)
    return
  }


  process.title = 'npm'


  var log = require('npmlog')
  log.pause() // will be unpaused when config is loaded.


  log.info('it worked if it ends with', 'ok')


  var path = require('path')
  var npm = require('../lib/npm.js')
  var npmconf = require('../lib/config/core.js')
  var errorHandler = require('../lib/utils/error-handler.js')


  var configDefs = npmconf.defs
  var shorthands = configDefs.shorthands
  var types = configDefs.types
  var nopt = require('nopt')


  // if npm is called as "npmg" or "npm_g", then
  // run in global mode.
  if (path.basename(process.argv[1]).slice(-1) === 'g') {
    process.argv.splice(1, 1, 'npm', '-g')
  }


  log.verbose('cli', process.argv)


  var conf = nopt(types, shorthands)
  npm.argv = conf.argv.remain
  if (npm.deref(npm.argv[0])) npm.command = npm.argv.shift()
  else conf.usage = true


  if (conf.version) {
    console.log(npm.version)
    return
  }


  if (conf.versions) {
    npm.command = 'version'
    conf.usage = false
    npm.argv = []
  }


  log.info('using', '[email protected]%s', npm.version)
  log.info('using', '[email protected]%s', process.version)


  process.on('uncaughtException', errorHandler)


  if (conf.usage && npm.command !== 'help') {
    npm.argv.unshift(npm.command)
    npm.command = 'help'
  }


  // now actually fire up npm and run the command.
  // this is how to use npm programmatically:
  conf._exit = true
  npm.load(conf, function (er) {
    if (er) return errorHandler(er)
    npm.commands[npm.command](npm.argv, errorHandler)
  })
})()

#!/usr/bin/env node
;(function () { // wrapper in case we're in module_context mode
  // windows: running "npm blah" in this folder will invoke WSH, not node.
  /*global WScript*/
  if (typeof WScript !== 'undefined') {
    WScript.echo(
      'npm does not work when run\n' +
        'with the Windows Scripting Host\n\n' +
        "'cd' to a different directory,\n" +
        "or type 'npm.cmd <args>',\n" +
        "or type 'node npm <args>'."
    )
    WScript.quit(1)
    return
  }


  process.title = 'npm'


  var log = require('npmlog')
  log.pause() // will be unpaused when config is loaded.


  log.info('it worked if it ends with', 'ok')


  var path = require('path')
  var npm = require('../lib/npm.js')
  var npmconf = require('../lib/config/core.js')
  var errorHandler = require('../lib/utils/error-handler.js')


  var configDefs = npmconf.defs
  var shorthands = configDefs.shorthands
  var types = configDefs.types
  var nopt = require('nopt')


  // if npm is called as "npmg" or "npm_g", then
  // run in global mode.
  if (path.basename(process.argv[1]).slice(-1) === 'g') {
    process.argv.splice(1, 1, 'npm', '-g')
  }


  log.verbose('cli', process.argv)


  var conf = nopt(types, shorthands)
  npm.argv = conf.argv.remain
  if (npm.deref(npm.argv[0])) npm.command = npm.argv.shift()
  else conf.usage = true


  if (conf.version) {
    console.log(npm.version)
    return
  }


  if (conf.versions) {
    npm.command = 'version'
    conf.usage = false
    npm.argv = []
  }


  log.info('using', '[email protected]%s', npm.version)
  log.info('using', '[email protected]%s', process.version)


  process.on('uncaughtException', errorHandler)


  if (conf.usage && npm.command !== 'help') {
    npm.argv.unshift(npm.command)
    npm.command = 'help'
  }


  // now actually fire up npm and run the command.
  // this is how to use npm programmatically:
  conf._exit = true
  npm.load(conf, function (er) {
    if (er) return errorHandler(er)
    npm.commands[npm.command](npm.argv, errorHandler)
  })
})()
另外还有
/Users/xxx/.gitbook/versions/3.2.3/node_modules/npm/bin/npm.cmd
/Users/xxx/.gitbook/versions/3.2.3/node_modules/npm/bin/npm
  console.info("in versions/3.2.3/node_modules/npm/bin/npm-cli.js")
结果:没输出。
回去注意到
/Users/xxx/.gitbook/versions/3.2.3/lib/plugins/installPlugin.js
    // Find a version to install
    return resolveVersion(plugin)
    .then(function(version) {
去看看
/Users/xxx/.gitbook/versions/3.2.3/lib/plugins/resolveVersion.js
/**
    Resolve a plugin dependency to a version


    @param {PluginDependency} plugin
    @return {Promise<String>}
*/
function resolveVersion(plugin) {
    var npmId = Plugin.nameToNpmID(plugin.getName());
    var requiredVersion = plugin.getVersion();


    if (plugin.isGitDependency()) {
        return Promise.resolve(requiredVersion);
    }
...
用:
function resolveVersion(plugin) {
    console.info("plugin=%o", plugin)
输出:
plugin=PluginDependency { "name": "google-adsense", "version": "*", "enabled": true }
function resolveVersion(plugin) {
    console.info("plugin=%o", plugin)
    
    var npmId = Plugin.nameToNpmID(plugin.getName());
    console.info("npmId=%o", npmId)
    var requiredVersion = plugin.getVersion();
    console.info("requiredVersion=%o", requiredVersion)


    if (plugin.isGitDependency()) {
        console.info("plugin.isGitDependency is True")
        return Promise.resolve(requiredVersion);
    }


    return initNPM()
    .then(function() {
        console.info("complete initNPM")
        console.info("npm.commands=%o", npm.commands)
        console.info("npm.commands.view=%o", npm.commands.view)
        return Promise.nfcall(npm.commands.view, [npmId + '@' + requiredVersion, 'engines'], true);
    })
输出:
plugin=PluginDependency { "name": "google-adsense", "version": "*", "enabled": true }
npmId='gitbook-plugin-google-adsense'
requiredVersion='*'
(node:2659) [DEP0079] DeprecationWarning: Custom inspection function on Objects via .inspect() is deprecated
complete initNPM
npm.commands={ [ac]: [Getter],
  [acc]: [Getter],
  [acce]: [Getter],
  [acces]: [Getter],
  access: [Getter],
  [add-]: [Getter],
  [add-u]: [Getter],
。。。
  [whoam]: [Getter],
  whoami: [Getter],
  [build]: [Getter],
  [unbuild]: [Getter],
  [xmas]: [Getter],
  [substack]: [Getter],
  [visnup]: [Getter] }
npm.commands.view={ [Function]
  [length]: 0,
  [name]: '',
  [arguments]: null,
  [caller]: null,
  [prototype]: { [constructor]: [Circular] },
  usage:
   'npm view [<@scope>/]<pkg>[@<version>] [<field>[.subfield]...]\n\naliases: v, info, show',
  completion:
   { [Function]
     [length]: 2,
     [name]: '',
     [arguments]: null,
     [caller]: null,
     [prototype]: { [constructor]: [Circular] } } }
看到是:
npm view [<@scope>/]<pkg>[@<version>] [<field>[.subfield]...]\n\naliases: v, info, show
想到去:
 [email protected]  ~/.gitbook/versions/3.2.3/node_modules/npm  bin/npm-cli.js --version
in versions/3.2.3/node_modules/npm/bin/npm-cli.js
3.9.2
-》实现了我们希望的,至少找到了:npm对应的二进制是哪个

转载请注明:在路上 » 【记录】研究搞懂gitbook内部调用npm去install插件的逻辑和相关代码

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
84 queries in 0.120 seconds, using 20.62MB memory