webpack chunk 讀出來是空的該怎麼辦

總之最近有需求所以用上了 webpack 的 code splitting,就在用爽爽以為世界為我所有的時候,碰到神秘的現象。

環境

為了稍微釐清一下關係,以下的主角分別稱為 A & B

A - 嵌入式的工具,設計為可以嵌入各種網站使用(使用 webpack code splitting)
B - 新的 project(使用 webpack),有嵌入 A 做進階使用

這天 B 需要嘗試加入 code splitting,目前只需要分成兩個 chunk,一個 chunk 代表一個 route。

簡單的 code splitting 示意寫法如下:

import dyna from '_util/createDynamicComponent';

const Main = dyna((resolve) => {
  require.ensure([], require => {
    resolve(require('_components/Main').default);
  });
});

照常理來說,webpack 會確保 require.ensure 的 callback 裡面需要執行的東西在讀進來之後才執行;然而,此處的 require('_components/Main') 在實際執行的時候,卻時不時是空的 {}

設身處地的想想,這個 bug 有多難 deeeeeeeeeeeeeeee

webpack magic

在經過多方交叉測試確認不是我程式碼這邊的問題之後,所有的矛頭指向了 webpack。但 webpack 的能力太強、文件寫得不夠詳盡,對我來說 code splitting 這件事就是一個 magic,也因此還真的不知道該怎麼 de webpack 的 bug。

於是我在 google 上搜尋各種可能的 keyword

webpack chunk load failed
webpack chunk doesn't load

然後實際上很莫名的會一直搜到它的文件,以及各種 tutorial 或 opinion 文章,頓時真是覺得這個生態系是不是有什麼問題...

直到我從上面的環境中 identify 了關鍵的可能原因,重新用了這個 keyword

webpack multiple instance

搜尋結果其實看起來還是一樣沒有一矢中的的感覺,不過答案其實默默地藏在第三個結果裡。

Ref: https://github.com/webpack/docs/wiki/configuration#outputjsonpfunction

output.jsonpFunction
The JSONP function used by webpack for asnyc loading of chunks.
A shorter function may reduce the filesize a bit. Use different identifier, when having multiple webpack instances on a single page.

output.jsonpFunction

有稍微 trace 一下的話,可以知道 webpack 想要載入 chunk 的時候會需要使用這個一個名為 webpackJsonp 的 global function (在 window 底下),而這個設定 output.jsonpFunction 就是用來設定這個 function name 的。

在同一個網頁上面有多個 webpack instance 的時候 (ex: AB 都是 webpack,而且都有做 code split),這個 jsonpFunction 的名字相同會讓兩者其中一方的 chunk loading 陷入錯亂(似乎是編號-based,而編號會混在一起)。

所以最後只需要把 Aoutput.jsonpFunction 改成比較 unique 的就解決了。

TL;DR

條件
  • 同一個頁面會用到兩個以上的 webpack instance
    (一般來說就是兩個從 webpack 面來看沒有相關的 bundle)
  • 有需要做 chunk 載入
需要
  • 透過 output.jsonpFunction 確保兩個 instance 的 jsonp function name 不同
webpack.config.js
var config = {
  ...
  output: {
    ...
    jsonpFunction: 'somethingPrettyUniqueJsonp'  // so important

  }
};

後記

是說 multiple webpack instance 需要改 jsonp function name 這種事情這麼重要,也太難找!!!!!!

尋找 YouTube 進度條上的流星

開始讀正文之前先來聽首歌吧!

記得當年 YouTube 進度條出來的時候好像造成一片轟動,突然之前大家爭先恐後 implement 它,蔚為風潮;而當年 implementation 中的佼佼者就是 NProgress,到了現在還是盤據一方(?)。

其實之前也不乏做過類似的進度條效果,不過從來沒有特別對 peg 的部分雕琢(或著說根本沒有加)。

什麼是 peg 呢? 來看一下 NProgress 裡面的一段 CSS code

/* Fancy blur effect */
#nprogress .peg {
  display: block;
  position: absolute;
  right: 0px;
  width: 100px;
  height: 100%;
  box-shadow: 0 0 10px #29d, 0 0 5px #29d;
  opacity: 1.0;

  -webkit-transform: rotate(3deg) translate(0px, -4px);
      -ms-transform: rotate(3deg) translate(0px, -4px);
          transform: rotate(3deg) translate(0px, -4px);
}

實際上看起來的效果是

這個小小的點綴其實為這個進度條增色了非常多,因為進度條本體的高度並不高,透過這個 peg 可以再它動作的時候達到比較好的吸引注意力的效果,讓使用者更容易意識到有什麼東西在動作中。

這個效果其實 YouTube 版本的進度條上面就有,不過我從來沒有好好正眼看過它(一閃即逝嘛)。最近的專案又做了類似 YouTube 的進度條,於是默默決定應該要好好地看一看 YouTube 的 peg 是怎麼做的,便開始了這次尋找流星的旅程。

Read on

週末長知識: 不換行空格

最近處裡一些 HTML 裡面的字串空白,發現在出現   的時候好像用 ' ' 會消不完全... 沒道理啊?

舉個例子

有沒有感覺到一點點的微妙,為何中間的空白不會被 split() 切開呢? 難道從 $(...).text() 取得的中間有些空白不是一般的空白?

接著把上面實驗中的字串拿來研究一下。

// 來源: 上面範例中的 $.trim($('#content').text())

var str = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.';

console.log(str.charCodeAt(str.indexOf('sit') - 1)));
// output: 160

知道 charcode 是 160 之後應該就很好搜尋囉,於是用 「charcode space 160」 去 google 了一下找到這篇文章:

White-space and character 160

So I used charCodeAt and found it was ASCII character 160. I looked up char code 160 and saw that it is a “Non-breaking space”. You would think that a “space” character would be trimmed. I looked at the jQuery code that does the trimming and the grep pattern uses \s. So, evidently you can’t use \s to catch the “Non-breaking space” in IE. I wonder why no one else has seen this.

乍看好像是古早年代的 IE 問題? 那我怎麼現在會在 modern browser 裡面碰到呢?

接著來試著搜尋中文 「char 160 空白」,發現相關的問題在各種地方出現...

突然就看到了 Wikipedia 的連結

眼尖的話會注意到原來在 HTML 裡面的 &nbps; 竟然是也是不換行空格的實現!!!!! 小時候填鴨式學的 HTML,只知道   是一種輸入空白的方法,原來它還有這層特別的含意... 更何況原來它根本不是空白!(說是也可以是啦)

原來 2009 年的 IE 是對的。(根據上面 2009 年的文章,當時的其他瀏覽器都把   輸出為一般的空白 ' ',但 IE 裡面用 regular expression /\s/ 還是 match 不到 '\u00a0')

總之現在 modern browser 們也都是把   轉為這個 '\u00a0',以後碰到類似的東西就不需要大驚小怪囉!
心裡有個底的話,debug 起來會快很多的。

最後補充一下,上面 2009 那篇文章的內容已經與現在瀏覽器的情況不符了。
文中附的 test 頁面 ,展示的 jQuery trim(text) 結果現在看起來是正確的,因為現在的瀏覽器已經確實把 '\u00a0' 視為空白的一種囉!

用 code 來說就是

'\u00a0\u00a0'.replace(/\s/g, '') === '';  // true

React 碎碎念: 艱困的新手之路

其實關注 React 的東西已經很久,直到最近剛好有機會就在新的專案跳坑下來,寫了兩個星期之後有很多事情覺得應該要寫下來做個紀錄。

至於為什麼叫碎碎念而不叫做筆記呢? 因為文章中個人抒發感想的部分可能也不在少數,又或著可能我沒有真心喜歡它(React)吧。

碎碎念大部分是個人意見,客觀部分敘述有錯誤歡迎指證。

正文

我真心覺得現在的 React 超難上手。

在 JS 的生態系統推進,以及各種工程師大大們的持續努力之下,想要上手現在的 React (可謂是 modern React)大概需要了解、會操作下面這些東西:

再補上一些可選的項目

當然如果上述這些都有統一而且很直覺的學習路徑也就罷了(用現在的英文說是 opinionated),但我想現在的 JS 精神就是要把所有東西都 modulize,所以往往我們光是 configure 環境就要花掉大把的精神與時間。

可以看一下 AngularClass 在去年年底對 React developers 做的調查,就知道是一個多麼充滿選擇的環境(菸)。

Read on