王二小

王二小 查看完整档案

填写现居城市  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 个人简介什么都没有

个人动态

王二小 收藏了文章 · 2020-12-04

前端异常监控-看这篇就够了

前端异常监控

如果debug是移除bug的流程,那么编程就一定是将bug放进去的流程。
如果没有用户反馈问题,那就代表我们的产品棒棒哒,对不对?

主要内容

  • Web规范中相关前端异常
  • 异常按照捕获方式分类
  • 异常的捕获方式
  • 日志上报的方式

前端异常类型(Execption)

WebIDLecma-262中的错误类型

  • ECMAScript exceptions <==> IDL 的简单异常

    当脚本代码运行时发生的错误,会创建Error对象,并将其抛出,除了通用的Error构造函数外,以下是另外几个ECMAScript 2015中定义的错误构造函数。

    • EvalError eval错误
    • RangeError 范围错误
    • ReferenceError 引用错误
    • TypeError 类型错误
    • URIError URI错误
    • SyntaxError 语法错误 (这个错误WebIDL中故意省略,保留给ES解析器使用)
    • Error 通用错误 (这个错误WebIDL中故意省略,保留给开发者使用使用)
  • DOMException 最新的DOM规范定义的错误类型集,兼容旧浏览的DOMError接口, 完善和规范化DOM错误类型。

    • IndexSizeError 索引不在允许的范围内
    • HierarchyRequestError 节点树层次结构是不正确的。
    • WrongDocumentError 对象是错误的
    • InvalidCharacterError 字符串包含无效字符。
    • NoModificationAllowedError 对象不能被修改。
    • NotFoundError 对象不能在这里被找到。
    • NotSupportedError 不支持的操作
    • InvalidStateError 对象是一个无效的状态。
    • SyntaxError 字符串不匹配预期的模式
    • InvalidModificationError 对象不能以这种方式被修改
    • NamespaceError 操作在XML命名空间内是不被允许的
    • InvalidAccessError 对象不支持这种操作或参数。
    • TypeMismatchError 对象的类型不匹配预期的类型。
    • SecurityError 此操作是不安全的。
    • NetworkError 发生网络错误
    • AbortError 操作被中止
    • URLMismatchError 给定的URL不匹配另一个URL。
    • QuotaExceededError 已经超过给定配额。
    • TimeoutError 操作超时。
    • InvalidNodeTypeError 这个操作的 节点或节点祖先 是不正确的
    • DataCloneError 对象不能克隆。

前端错误异常按照捕获方式分类

  • [x] 语法错误
  • [x] 运行时异常
  • [x] 资源加载异常

    • img
    • script
    • link
    • audio
    • video
    • iframe
    • ...外链资源的DOM元素
  • [x] 异步请求异常

    • XMLHttpRequest
    • fetch
  • [x] Promise异常
  • [ ] CSS中资源异常

    • @font-face
    • background-image
    • ...暂时无法捕获

前端错误异常的捕获方式

  • try-catch (ES提供基本的错误捕获语法)

    • 只能捕获同步代码的异常
    • 回调
    • setTimeout
    • promise
  • window.onerror = cb (DOM0)

    • img
    • script
    • link
  • window.addEventListener('error', cb, true) (DOM2)
  • window.addEventListener("unhandledrejection", cb) (DOM4)
  • Promise.then().catch(cb)
  • 封装XMLHttpRequest&fetch | 覆写请求接口对象

try-catch-finally

将能引发异常的代码块放到try中,并对应一个响应,然后有异常会被捕获

  try {
    // 模拟一段可能有错误的代码
    throw new Error("会有错误的代码块")
  } catch(e){
    // 捕获到try中代码块的错误得到一个错误对象e,进行处理分析
    report(e)
  } finally {
    console.log("finally")
  }

onerror事件

window.onerror

当JavaScript运行时错误(包括语法错误)发生时,window会触发一个ErrorEvent接口的事件,并执行window.onerror();

但这里有个信息要注意,语法错误会导致出现语法错误的那个脚本块执行失败,所以语法错误会导致当前代码块运行终止,从而导致整个程序运行中断,如果语法错误这个发生在我们的错误监控语句块中,那么我们就什么也监控不到了。

/**
 * @description 运行时错误处理器
 * @param {string} message 错误信息
 * @param {string} source 发生错误的脚本URL
 * @param {number} lineno 发生错误的行号
 * @param {number} colno 发生错误的列号
 * @param {object} error Error对象
 */
function err(message,source,lineno,colno,error) {...}
window.onerror = err

element.onerror

当一项资源(如<img><script>)加载失败,加载资源的元素会触发一个Event接口的error事件,并执行该元素上的onerror()处理函数。

element.onerror = function(event) { ... } //注意和window.onerror的参数不同

注意:这些error事件不会向上冒泡到window,不过能被单一的window.addEventListener捕获。

window.addEventListener

addEventListener相关的一些内容

W3C DOM2 Events规范中提供的注册事件监听器的方法, 在这之前均使用
el.onclick的形式(DOM0 规范的基本内容,几乎所有浏览器都支持)。

注意: 接口的几种语法

error事件捕获资源加载错误

资源加载失败,不会冒泡,但是会被addEventListener捕获,所以我们可以指定在加载失败事件的捕获阶段捕获该错误。

注意: 接口同时也能捕获运行时错误。

window.addEventListener("error", function(e) {
    var eventType = [].toString.call(e, e);
    if (eventType === "[object Event]") { // 过滤掉运行时错误
      // 上报加载错误
      report(e)
    }
  },
  true
);

unhandledrejection事件捕获Promise异常

最新的规范中定义了 unhandledrejection事件用于全局捕获promise对象没有rejection处理器时异常情况。

window.addEventListener("unhandledrejection", function (event) {
    // ...your code here to handle the unhandled rejection...

    // Prevent the default handling (error in console)
    event.preventDefault();
});

Promise.then().catch(cb).finally()

Promise中的错误会被Promise.prototype.catch捕获,所以我们通过这种方式捕获错误,这包括一些不支持unhandledrejection事件的环境中promisede polyfill实现。

new Promise(function(resolve, reject) {
  throw 'Uncaught Exception!';
}).catch(function(e) {
  console.log(e); // Uncaught Exception!
});

封装XMLHttpRequest&fetch | 覆写请求接口对象

// 覆写XMLHttpRequest API
if(!window.XMLHttpRequest) return;
  var xmlhttp = window.XMLHttpRequest;
  var _oldSend = xmlhttp.prototype.send;
  var _handleEvent = function (event) {
      if (event && event.currentTarget && event.currentTarget.status !== 200) {
        report(event)
      }
  }
  xmlhttp.prototype.send = function () {
      if (this['addEventListener']) {
          this['addEventListener']('error', _handleEvent);
          this['addEventListener']('load', _handleEvent);
          this['addEventListener']('abort', _handleEvent);
          this['addEventListener']('close', _handleEvent);
      } else {
          var _oldStateChange = this['onreadystatechange'];
          this['onreadystatechange'] = function (event) {
              if (this.readyState === 4) {
                  _handleEvent(event);
              }
              _oldStateChange && _oldStateChange.apply(this, arguments);
          };
      }
      return _oldSend.apply(this, arguments);
  }

// 覆写fetch API
if (!window.fetch) return;
var _oldFetch = window.fetch;
window.fetch = function() {
  return _oldFetch
    .apply(this, arguments)
    .then(function(res){
      if (!res.ok) {
        // True if status is HTTP 2xx
        report(res)
      }
      return res;
    })
    .catch(function(error){
      report(res)
    });
}

日志上报的方式

  • 异步请求上报, 后端提供接口,或者直接发到日志服务器
  • img请求上报, url参数带上错误信息

    • eg:(new Image()).src = 'http://baidu.com/tesjk?r=tksjk'

注意跨源脚本异常

当加载自不同域的脚本中发生语法错误时,为避免信息泄露,语法错误的细节将不会报告,而代之简单的 "Script error."

由于同源策略影响,浏览器限制跨源脚本的错误访问,这样跨源脚本错误报错信息如下图:

跨源的脚本的异常

在H5的规定中,只要满足下面俩个条件,是允许获取跨源脚本的错误信息的。

  1. 客户端在script标签上增加crossorigin属性;
  2. 服务端设置js资源响应头Access-Control-Origin:*(或者是域名)。

扩展阅读

业界已经有的监控平台

  • Sentry开源
  • 阿里的ARMS
  • fundebug
  • FrontJS

几个异常监控的问题

  • 如何保证大家提交的代码是符合预期的? 如何了解前端项目的运行是否正常,是否存在错误?

    代码质量体系控制和错误监控以及性能分析

  • 如果用户使用网页,发现白屏,现在联系上了你们,你们会向他询问什么信息呢?先想一下为什么会白屏?

    我们以用户访问页面的过程为顺序,大致排查一下

    1. 用户没打开网络
    2. DNS域名劫持
    3. http劫持
    4. cdn或是其他资源文件访问出错
    5. 服务器错误
    6. 前端代码错误
    7. 前端兼容性问题
    8. 用户操作出错

通过以上可能发生错误的环节,我们需要向用户手机一下以下的用户信息

    1. 当前的网络状态
    2. 运营商
    3. 地理位置
    4. 访问时间
    5. 客户端的版本(如果是通过客户端访问)
    6. 系统版本
    7. 浏览器信息
    8. 设备分辨率
    9. 页面的来源
    10. 用户的账号信息
    11. 通过performance API收集用户各个页面访问流程所消耗的时间
    12. 收集用户js代码报错的信息
    • 如果我们使用了脚本代码压缩,然而我们又不想将sourcemap文件发布到线上,我们怎么捕获到错误的具体信息?
    • CSS文件中也存在引用资源,@font-face, background-image ...等这些请求错误该如何进行错误捕获?

    总结

    • Web规范中相关前端异常

      • DOM处理异常
      • ECMAScript处理异常
    • 异常按照捕获方式分类

      • 运行时异常
      • 资源加载异常
      • 异步请求异常
      • Promise异常
    • 异常的捕获方式

      • try-catch (ES提供基本的错误捕获语法)

        • 只能捕获同步代码的异常
        • 回调
        • setTimeout
        • promise
      • window.onerror = cb (DOM0)

        • img
        • script
        • link
      • window.addEventListener('error', cb, true) (DOM2)
      • window.addEventListener("unhandledrejection", cb) (DOM4)
      • Promise.then().catch(cb)
      • 封装XMLHttpRequest&fetch | 覆写请求接口对象

    注意点:跨源脚本异常的捕获

    • 日志上报的方式

      • 异步请求上报
      • new img上报 避免跨域问题
    • 扩展阅读

      • 业界已有的异常监控平台
      • 几个跟异常监控有关的问题

    ==========12月13日修正===========
    语法错误的捕获有些特殊,一般情况下,语法错误在开发阶段就会报错,很容易解决。但是如果在上线之后程序运行在不兼容的环境中也可能存在语法错误,引用的外部脚本存在语法错误等情况,我们就可以捕获到一个包含错误信息的错误对象,而不仅仅是“Uncaught SyntaxError: Invalid or unexpected token”

    查看原文

    王二小 收藏了文章 · 2020-12-01

    【JS基础】sourceMap是个啥

    为啥用sourceMap

    这几天在搞前端错误日志,做过线上发布的都知道,我们发布到生产环境的代码,一般都有如下步骤:

    • 压缩混淆,减小体积
    • 多个文件合并,减少HTTP请求数
    • 通过编译或者转译,将其他语言编译成JavaScript

    这三个步骤,都使得实际运行的代码不同于开发代码,不管是 debug 还是捕获线上的报错,都会变得困难重重。

    解决这个问题的方法,就是使用sourceMap

    啥是sourceMap

    简单说,sourceMap就是一个文件,里面储存着位置信息。

    仔细点说,这个文件里保存的,是转换后代码的位置,和对应的转换前的位置。

    有了它,出错的时候,通过断点工具可以直接显示原始代码,而不是转换后的代码。

    sourceMap长啥样

    通过webpack等工具,我们可以使用 sourceMap,这里不细说配置方法,可以看这里

    sourceMap是一个map文件,与源码在同一个目录下。

    在压缩代码的最后一行,会有这样的一个引用:

    //# sourceMappingURL=app.js.map

    指向的就是我们的map文件。

    sourceMap的格式如下:

    {
        version : 3, //SourceMap的版本,目前为3
        sources: ["foo.js", "bar.js"], //转换前的文件,该项是一个数组,表示可能存在多个文件合并
        names: ["src", "maps", "are", "fun"], //转换前的所有变量名和属性名
        mappings: "AACvB,gBAAgB,EAAE;AAClB;", //记录位置信息的字符串
        file: "out.js", //转换后的文件名
        sourcesContent: ["\t// The module cache\n", "xxx"], //转换前的文件内容列表,与sources列表依次对应
        sourceRoot : "" //转换前的文件所在的目录。如果与转换前的文件在同一目录,该项为空
    }

    其他的都很好解释,我们详细说一下mappings属性。

    mappings

    "AACvB,gBAAgB,EAAE;AAClB;"为例:

    • 每个分号对应转换后源码的一行;
    • 每个逗号对应转换后源码的一个位置;
    • AACvB代表该位置转换前的源码位置,以VLQ编码表示;

    位置对应的原理

    位置关系的保存经历了诸多步骤和优化,这个不详细说了,想看的可以看这里,我们只说最后的结果。

    在每个位置中:

    • 第一位,表示这个位置在【转换后代码】的第几列。
    • 第二位,表示这个位置属于【sources属性】中的哪一个文件。
    • 第三位,表示这个位置属于【转换前代码】的第几行。
    • 第四位,表示这个位置属于【转换前代码】的第几列。
    • 第五位,表示这个位置属于【names属性】的哪一个变量。

    举例

    假设现在有a.js,内容为feel the force,处理后为b.js,内容为the force feel

    the为例,它在输出中的位置是(0,0),a.jssources的第1个(这里只是举例),输入中的位置是(0,5),thenames的第2个(这里只是举例)。

    那么映射关系为:
    0 1 0 5 2

    最后将 01052 表示为 Base64 VLQ 即可。

    说明:

    • 所有的值都是以0作为基数
    • 第五位不是必需的,如果该位置没有对应names属性中的变量,可以省略第五位
    • 每一位都采用VLQ编码表示,由于VLQ编码是可变长的,所以每一位可以由多个字符构成
    • 为什么不保存转换后代码的行号,因为我们输出的文件总是一行,这样输出的行号就可以省略,因为都是0,没必要写出来
    • 对于输出后的位置来说,到后边会发现它的列号特别大,为了避免这个问题,采用相对位置进行描述

    相对位置是啥呢,看示意图:

    第一次记录的输入位置和输出位置是绝对的,往后的输入位置和输出位置都是相对上一次的位置移动了多少,例如the的输出位置为(0,-10),因为thefeel的左边数10下才能到这个位置。

    VLQ编码

    VLQVariable-length quantity 的缩写,是一种通用的、使用任意位数的二进制来表示一个任意大的数字的一种编码方式。这种编码最早用于MIDI文件,后来被多种格式采用,它的特点就是可以非常精简地表示很大的数值,用来节省空间。

    这种编码需要用最高位表示连续性,如果是1,代表这组字节后面的一组字节也属于同一个数;如果是0,表示该数值到这就结束了。

    这样干巴巴说不太容易懂,还是举个栗子说明一下吧。

    如何对数值137进行VLQ编码:

    步骤结果
    将137改写成二进制形式10001001
    七位一组做分组,不足的补00000001 0001001
    最后一组开头补0,其余补110000001 00001001

    所以,137的VLQ编码形式为10000001 00001001

    Base64 VLQ

    与一般的VLQ的区别:

    • 一个Base64字符只能表示 6bit(2^6)的数据
    • Base64 VLQ需要能够表示负数,于是用最后一位来作为符号标志位。
    • 由于只能用6位进行存储,而第一位表示是否连续的标志,最后一位表示正数/负数。中间只有4位,因此一个单元表示的范围为[-15,15],如果超过了就要用连续标识位了。

    表示正负的方式:

    • 如果这组数是某个数值的VLQ编码的第一组字节,那它的最后一位代表"符号",0为正,1为负;
    • 如果不是,这个位没有特殊含义,被算作数值的一部分。

    我们再来举个栗子说明下使用方法。

    如何对数值137进行Base64 VLQ编码:

    步骤结果
    将137改写成二进制形式10001001
    127是正数,末位补0100010010
    五位一组做分组,不足的补001000 10010
    将组倒序排序10010 01000
    最后一组开头补0,其余补1110010 001000
    转64进制y和I

    所以 137 通过Base64 VLQ表示为yl

    可以看出:

    • Base64 VLQ中,编码顺序是从低位到高位
    • 而在VLQ中,编码顺序是从高位到低位

    参考文章

    查看原文

    王二小 收藏了文章 · 2020-11-29

    你真的知道 Cookie 吗? SameSite 、 Secure 、 HttpOnly

    这两天(已经是一个多月前了) SF 上面很多 cookie 的问题,然后还有个 cookie 相关的付费问答。
    所以咱们今天来这么一节,废话多说点,先说说大体问题方向。

    1. 跨域如何携带 cookie
    2. chrome 80 版本加强隐私。SameSite=Lax 为默认值,禁止了一部分场景携带 cookie。

    1585542538409.png

    Cookie

    用于服务端辨别用户身份储存在用户本地的数据。
    可以解决客户端与服务端会话状态的问题,这个状态是指后端服务的状态而非通讯协议(HTTP)的状态。

    Cookie 值的存储

    域名下的 cookie 一般来说是最大是 4KB。当然大家也不会真的放这么多。

    Name / Value

    存储是以 Name=Value 的形式。

    Domain / Path 作用域

    Domain 是限制域名,设置为 www.lilnong.top 的话,cors.lilnong.top 就获取不到了。
    Path 是限制路径,如果设置为 /cors 的话,/api 下的请求就不会携带该 cookie

    Expires / Max-Age 有效性

    Expires 是当前 Cookie 的过期时间,默认是会话级别。

    Max-Age 是当前 Cookie 经过多少秒失效。

    1. 大于 0 是计算经过多少秒失效
    2. 等于 0 是会话级别,关闭浏览器就失效
    3. 小于 0 是指 cookie 无效,立即删除

    Max-Age 的优先级比 Expires 更高。

    HttpOnly 安全性

    设置以后客户端脚本就无法通过 document.cookie 等方式获取。
    有助于避免 XSS 攻击。

    Secure 安全性

    设置以后客户端只有 HTTPS 协议下才会发送给服务端。
    使用 HTTPS 安全协议,可以保护 Cookie 在浏览器和 Web 服务器间的传输过程中不被窃取和篡改

    SameSite 安全性

    可以设置 Cookie 在什么场景下会被发送。从而屏蔽跨站时发送 cookie,用于阻止跨站请求伪造攻击(CSRF)

    SameSite 可以设置下面三个值:

    1. Strict 只允许同站请求携带 Cookie。比如 lilnong.top 跳转到 www.lilnong.top/cors/,就属于同站。
    2. Laxchrome 80 后的默认值) 允许部分第三方请求场景 携带Cookie。
    3. Nonechrome 80 前的默认值) 无论是否跨站都会发送 Cookie。必须同时加上 Secure 属性,否则无效,也就是说只支持 HTTPS。

      IOS 12 的 Safari 以及老版本的一些 Chrome 会把 SameSite=none 识别成 SameSite=Strict,所以服务端必须在下发 Set-Cookie 响应头时进行 User-Agent 检测,对这些浏览器不下发 SameSite=none 属性

    接下来我们来比对一下跨站的各个场景,Demo 晚点给吧。

    场景类型场景备注StrictLaxNone
    链接<a href>不发
    预加载<link rel="prerender">不发
    get 表单<form method="get">不发
    post 表单<form method="post">不发不发
    iframe<iframe src>不发不发
    AJAX<a href>不发不发
    图片<img src>不发不发
    scriptjsonp

    查看 Cookie

    1. 开发者工具 -> application -> Storage -> Cookies -> 选择对应的域名
      image.png
    2. document.cookie 这里只能获取到允许获取 (HTTPOnly) 的
    3. 去本地文件中查看。因为他是持久化的,所以存放在磁盘上。一些优化管家可以删除垃圾(缓存文件)。

    设置 Cookie

    1. 响应头中的 Set-Cookie,这个属于最常用的方式。
      Set-Cookie: key1=value1; path=path; domain=domain; max-age=max-age-in-seconds; expires=date-in-GMTString-format; secure; httponly; SameSite=None
    2. document.cookie="key=value" 这种是前端设置 cookie 。

    概念解释

    同站 (same-site)、跨站 (cross-site)」与「第一方 (first-party)、第三方 (third-party)」这两个概念是等价的。
    但是和 浏览器同源策略(SOP) 中的「同源 (same-origin)、跨域 (cross-origin)」是完全不同的概念

    同站和跨站

    同站是指二级域名+顶级域名,相等即可。
    比如 www.lilnong.top 解析一下就是 主机名.二级域名.顶级域名,所以判断规则还是比较松的。

    eTLD 表示有效顶级域名,注册于 Mozilla 维护的公共后缀列表(Public Suffix List)中,例如,.com、.co.uk、.github.io 等。
    eTLD+1 表示,有效顶级域名+二级域名,例如 taobao.com 等。

    同源和跨域

    同源策略的同源是指两个 URL 的协议/主机名/端口一致

    域名备注(请求 https://www.lilnong.top
    https://www.lilnong.top(同源)同协议、同主机、同端口
    http://www.lilnong.top(跨域)不同协议
    https://www.lilnong.top:8081(跨域)不同端口
    http://www.lilnong.top:8081(跨域)不同协议、不同端口
    https://cors.lilnong.top(跨域)不同主机

    总结

    1. 基于上面关于 Cookie 的介绍我们可以知道,Chrome 跨站时 Cookie 会因为 SameSite 的设置导致异常。
    2. 跨域时要携带 Cookie 时,我们还要注意 withCredentials 的设置。然后就是清除 cookie,重启浏览器了。

    微信公众号:前端linong

    clipboard.png

    参考文章

    1. 浏览器系列之 Cookie 和 SameSite 属性
    2. public_suffix_list
    3. PUBLIC SUFFIX LIST
    4. Cookie 的 SameSite 属性
    5. 当浏览器全面禁用三方 Cookie
    查看原文

    王二小 关注了用户 · 2020-10-24

    前端小智 @minnanitkong

    我不是什么大牛,我其实想做的就是一个传播者。内容可能过于基础,但对于刚入门的人来说或许是一个窗口,一个解惑之窗。我要先坚持分享20年,大家来一起见证吧。

    关注 9498

    王二小 回答了问题 · 2020-10-19

    npm 全局安装出错 windows10

    经过一天的查找,发现是用户下的npmrc文件配置错误,将文件夹下的

    prefix=F:\Programfiles\nodejs\node_modules\npm
    registry=https://registry.npm.taobao.org

    修改为

    prefix=F:\Programfiles\nodejs
    registry=https://registry.npm.taobao.org

    问题成功解决,因为我去查找问题的时候发现,发现F:\Programfiles\nodejs这个文件夹下面有npm命令,所以就尝试了一下前面所说的更改,问题成功解决。

    关注 1 回答 2

    王二小 提出了问题 · 2020-10-19

    npm 全局安装出错 windows10

    我的node是用nvm安装的,用户下的npmrc配置文件如下

    prefix=F:\Programfiles\nodejs\node_modules\npm
    registry=https://registry.npm.taobao.org

    在用nvm切换后的那个node目录下npmrc文件无配置,

    nvm use 12.18.4

    切换到node12.18.4 后,在项目文件夹'F:\draft\demo06'执行命令

    npm i -g webpack

    报错

    $ npm i -g webpack
    npm ERR! code EEXIST
    npm ERR! path F:\Programfiles\nodejs\node_modules\npm\node_modules\@babel\parser\bin\babel-parser.js
    npm ERR! dest F:\Programfiles\nodejs\node_modules\npm\parser
    npm ERR! EEXIST: file already exists, cmd shim 'F:\Programfiles\nodejs\node_modules\npm\node_modules\@babel\parser\bin\babel-parser.js' -> 'F:\Programfiles\nodejs\node_modules\npm\parser'
    npm ERR! File exists: F:\Programfiles\nodejs\node_modules\npm\parser
    npm ERR! Remove the existing file and try again, or run npm
    npm ERR! with --force to overwrite files recklessly.
    
    npm ERR! A complete log of this run can be found in:
    npm ERR!     C:\Users\wangml\AppData\Roaming\npm-cache\_logs\2020-10-18T08_58_12_166Z-debug.log

    并且我也执行了命令

    npm i -g gulp

    安装成功,但是用gulp -v测试,报错

    bash: gulp: command not found

    npm 的配置文件如下

    $ npm config list
    ; cli configs
    metrics-registry = "https://registry.npm.taobao.org/"
    scope = ""
    user-agent = "npm/6.14.6 node/v12.18.4 win32 x64"
    
    ; userconfig C:\Users\wangml\.npmrc
    prefix = "F:\\Programfiles\\nodejs\\node_modules\\npm"
    registry = "https://registry.npm.taobao.org/"
    
    ; node bin location = F:\Programfiles\nodejs\node.exe
    ; cwd = F:\draft\demo06
    ; HOME = C:\Users\wangml
    ; "npm config ls -l" to show all defaults.

    以上命令操作均在目录F:\draft\demo06下进行的,前端小白,求大神解救

    关注 1 回答 2

    王二小 关注了专栏 · 2020-08-02

    js基础

    js基础知识

    关注 246

    王二小 关注了专栏 · 2020-08-02

    进击的大前端

    前端工程师,底层技术人。 思否2020年度“Top Writer”! 掘金“优秀作者”! 开源中国2020年度“优秀源创作者” 分享各种大前端进阶知识! 关注公众号【进击的大前端】第一时间获取高质量原创。 更多文章和示例源码请看:https://github.com/dennis-jiang/Front-End-Knowledges

    关注 11003

    王二小 关注了专栏 · 2020-08-02

    程序员哆啦A梦

    达达前端技术社群:囊括前端Vue、JavaScript、数据结构与算法、实战演练、Node全栈一线技术,紧跟业界发展步伐,一个热爱前端的达达程序员。

    关注 10209

    王二小 关注了专栏 · 2020-08-02

    技术风暴

    关注公众号「关山不难越」学习更多前端进阶知识。 Classical is something not fade,but grow more precious with time pass by,so is dream id dream.

    关注 5136

    认证与成就

    • 获得 0 次点赞
    • 获得 2 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 2 枚铜徽章

    擅长技能
    编辑

    (゚∀゚ )
    暂时没有

    开源项目 & 著作
    编辑

    (゚∀゚ )
    暂时没有

    注册于 2020-08-02
    个人主页被 208 人浏览