webpack + vue 在dev和production模式下的小小區別

来源:https://www.cnblogs.com/cqhaibin/archive/2018/04/21/8902139.html
-Advertisement-
Play Games

上周的某一天,和一位同樣是前端技術極度愛好的開發者朋友聊天,他在提出了一個問題,他寫的vue程式為什麼在dev模式運行良好,而在production模式就直接報錯了。這讓我感到驚訝,還有這麼神奇的事情。今就把這個歷險記道給大伙聽聽,看能從中學習到什麼? 一、還原現場 朋友在看到我的驚訝後,分分就把他 ...


     上周的某一天,和一位同樣是前端技術極度愛好的開發者朋友聊天,他在提出了一個問題,他寫的vue程式為什麼在dev模式運行良好,而在production模式就直接報錯了。這讓我感到驚訝,還有這麼神奇的事情。今就把這個歷險記道給大伙聽聽,看能從中學習到什麼?

一、還原現場

朋友在看到我的驚訝後,分分就把他出錯的demo發給了,本地運行,事故現場重現: image

二、排查嫌疑對象

既然現象是必現,要麼是自己的代碼出了問題,要麼就是vue有Bug(心裡莫名的偷笑,大伙都懂的)。

2.1 代碼文件結構和源碼展示

image
從代碼結構看,沒有好說的。就是用vue-cli創建的模板開發項目,其保增加了service層而已。經過我多年來的經驗,將嫌疑放到了service/index.js和components/HellowWorld.vue兩個文件上。

  • service/index.js代碼
let item = {};
item.result = 22222;
item.do = callBack => {
  return callBack({ result: this.a.result });
};

export default item;
  • HelloWorld.vue代碼(只展示了js代碼部分)
import service from "@/service/index"
export default {
  name: 'HelloWorld',
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  },
  mounted () {
    service.do(item => {
      this.msg = item.result
    })
  }
}

簡要邏輯說明:

  • HelloWorld.vue引用了service/index.js文件
  • service/index.js中定義了do方法,且接受一個callback參數(使用了es6的箭頭函數)
  • HelloWorld.vue在mounted方法中調用了do方法,且傳入了一個函數表達式(也使用了箭頭函數)

2.2 報錯位置偵查

通過運行結果對比圖,可以看出production模式下的運行是有報錯,在達里我們放大他的報錯位置:
image
     看到這裡,你是否有想破口大罵的衝動,怎麼會this.a.result呢,這代碼明顯有錯誤吧。然後我迅速查閱了他給的demo代碼,見service/index.js中的do方法,確實是怎麼樣寫的。立刻,我略帶鄙視的口吻質問我的那位朋友,你這個幾年的代碼白寫了吧,居然能犯這麼低級的錯誤。我直接把這個錯誤現場圖扔給了他。   

     馬上,他回了一個更為鄙視的表情,那為什麼我的dev模式能正常運行呢。我立即無語且尷尬。因為確實他的dev模式運行是正常的,只有在production模式下才出的問題啊。

2.3 重點分析嫌疑對象

    經過上述的分析和折騰,我們可以初步確定問題點就在service/index.js中do方法中和this上。也就是說在dev模式下這個this.a上是有result這個屬性的,而在production模式下this連這個a屬性都沒有了。

     作為老鳥的我,突然想到,dev模式和production模式都是運行在有sourcemap的的情況下的。這很不利用我們看編譯後的代碼。於是,我關閉了chrome瀏覽器的sourcemap功能,兩種模式下代碼如下:

  • dev模式下的運行代碼:
    image
    註意三個紅框處的代碼,webpack在dev模式下代碼文件是沒有合併成一個文件的,而是遵行commanJs規範,進行模式化載入的,而他對這個service/index.js這個模式導出時,用的名稱正是a。也就是解釋了在dev模式下this.a為什麼會有效,他的this.a.result有值,則是因為他雖然是單文件模式化載入,但其文件中的js代碼還是被bable做了轉換,將箭頭運算符轉換為了es5可執行的代碼。所以this.a.result是有值的。

 

  • production模式下的運行代碼:
    image
         看這段代碼是否有些頭大,其實從中我們只需要關心l這個變數的值,經測試發現,他的值不service/index.js中導出的對象,而是瀏覽器全局對象window。這就是為什麼production模式下的代碼不能正常運行的問題了。

三、我的推理和總結

      通過上述分析,可以大致推理出webpack在dev模式下是按照commonJs模式將各個文件獨立模式化載入和引用,而Build之後,各個文件模塊被合併成了一個,且對servcie/index.js進行了直接導出。再中上箭頭函數對this指向的處理,就造成了this.a無效了。
     在這個demo中就算把service/index.js中的this指向處理好了,但其值還是會正常顯示,原因在於vue組件中的mounted方法中也用到了箭頭函數,其this的指向在運行時也會不正確。具體解釋如下:

    註意,不要在實例屬性或者回調函數中(如 vm.$watch('a', newVal => this.myMethod()))使用箭頭函數。因為箭頭函數綁定父級上下文,所以 this 不會像預想的一樣是 Vue 實例,而且 this.myMethod 是未被定義的。

vue官網說明地址:https://cn.vuejs.org/v2/guide/instance.html

3.1 原因總結

  • this.a為什麼可以訪問,是因為webpack的dev下編譯是單個文件模式化引用導致的
  • vue組件的mounted中用不可使用箭頭函數,這個vue的特性,官網可見。
  • 示例代碼下載

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • npm作為下載node附送的大禮包,大家一定不會陌生。 然而關於npm,估計大量的只是用到npm install XXX以及npm run XXX。 其實這裡邊還有很多有意思的命令&參數。關於npm,大概有兩個作用: 下載相關的操作 下載主要就是圍繞著install這一個命令來的。 install ...
  • 建議儘量都使用 ,原因如下: 一致性:使用==對一致性沒有任何好處,那麼為什麼不避免使用呢。 簡單和性能:一般來說, 是最簡單的操作符,因為它不用進行類型轉換。JavaScript引擎的性能參差不齊,但是在大部分瀏覽器中 比==速度更快。 即使會自動轉換,但並不總是按你需要的方式轉換:比如7+“3” ...
  • ``` /* * 需求:給圖片的src地址前面增加為assets * * 1. 將需要匹配的內容原封不動的寫入正則表達式 * 2. 將改變的內容替換為.*? * 3. 將.*?添加(),目的是為了能夠將src中的內容單獨匹配一次作為匹配結果 * 4.通過replace將內容替換 * content.... ...
  • undefined和null與任何有意義的值比較返回的都是false,但是null與undefined之間互相比較返回的是true。 console.log(null == false); //false console.log(null == true); //false console.log( ...
  • 在做這個功能時,圖片被擋住了。。 解決辦法 在這個圖片的css裡加上z-index:數字;(數字可以為正也可以為負數) z-index:1肯定在z-index:-1的上面 用這個屬性來給div分層 是個不錯的選擇 ...
  • 運用摺疊面板後 可以讓頁面更加整潔 有什麼不懂的可以留言 代碼放到底部 需要引入的文件 JQuery代碼: html代碼 <div class="layui-colla-item"> <div class="layui-colla-title" style="background-color: #e ...
  • 以往 HTML 的 input 輸入框,無法即時(實時)反映使用者(用戶)的輸入內容。現在 HTML5 新增的 input 事件,可達成此一需求。 ...
  • input輸入框<div id="top-title" style="position: relative"> <img class="img-responsive center-block" alt="" src="" style="float:left;z-index: 999;position ...
一周排行
    -Advertisement-
    Play Games
  • 前言 在我們開發過程中基本上不可或缺的用到一些敏感機密數據,比如SQL伺服器的連接串或者是OAuth2的Secret等,這些敏感數據在代碼中是不太安全的,我們不應該在源代碼中存儲密碼和其他的敏感數據,一種推薦的方式是通過Asp.Net Core的機密管理器。 機密管理器 在 ASP.NET Core ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 順序棧的介面程式 目錄順序棧的介面程式頭文件創建順序棧入棧出棧利用棧將10進位轉16進位數驗證 頭文件 #include <stdio.h> #include <stdbool.h> #include <stdlib.h> 創建順序棧 // 指的是順序棧中的元素的數據類型,用戶可以根據需要進行修改 ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • C總結與剖析:關鍵字篇 -- <<C語言深度解剖>> 目錄C總結與剖析:關鍵字篇 -- <<C語言深度解剖>>程式的本質:二進位文件變數1.變數:記憶體上的某個位置開闢的空間2.變數的初始化3.為什麼要有變數4.局部變數與全局變數5.變數的大小由類型決定6.任何一個變數,記憶體賦值都是從低地址開始往高地 ...
  • 如果讓你來做一個有狀態流式應用的故障恢復,你會如何來做呢? 單機和多機會遇到什麼不同的問題? Flink Checkpoint 是做什麼用的?原理是什麼? ...
  • C++ 多級繼承 多級繼承是一種面向對象編程(OOP)特性,允許一個類從多個基類繼承屬性和方法。它使代碼更易於組織和維護,並促進代碼重用。 多級繼承的語法 在 C++ 中,使用 : 符號來指定繼承關係。多級繼承的語法如下: class DerivedClass : public BaseClass1 ...
  • 前言 什麼是SpringCloud? Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的開發便利性簡化了分散式系統的開發,比如服務註冊、服務發現、網關、路由、鏈路追蹤等。Spring Cloud 並不是重覆造輪子,而是將市面上開發得比較好的模塊集成進去,進行封裝,從 ...
  • class_template 類模板和函數模板的定義和使用類似,我們已經進行了介紹。有時,有兩個或多個類,其功能是相同的,僅僅是數據類型不同。類模板用於實現類所需數據的類型參數化 template<class NameType, class AgeType> class Person { publi ...
  • 目錄system v IPC簡介共用記憶體需要用到的函數介面shmget函數--獲取對象IDshmat函數--獲得映射空間shmctl函數--釋放資源共用記憶體實現思路註意 system v IPC簡介 消息隊列、共用記憶體和信號量統稱為system v IPC(進程間通信機制),V是羅馬數字5,是UNI ...