react 腳手架打包不生成 sourceMap 的解決方案

react 腳手架打包不生成 sourceMap 的解決方案

前言

我相信很多前端工程師都跟我一樣,用慣了開源的項目腳手架工具以後,都不習慣自己配置 webpack 了。

經常聽同行們開玩笑說,某某某個公司要啓動一個項目,所有的人員都配置好了,就缺一個首席 webpack 工程師了。

雖然是一句玩笑話,但是從側面也反映出來了,想把 webpack 配置好,是不多麼不容易的事情。自己動手給項目配置 webpack,經常動不動會出現版本不兼容的情況,打包出錯的情況。

不知道是出於什麼考慮,開源的這些腳手架,默認情況下,打包項目的過程中,都會生成 souceMap。如果你不清楚什麼是 souceMap,那麼你可以下面這些頁面詳細瞭解一下:

  1. https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/SourceMap
  2. https://developer.mozilla.org/zh-CN/docs/Tools/Debugger/How_to/Use_a_source_map

對於新手用戶來說,如果不瞭解這個情況,直接把打包以後的代碼上線了,那麼很可能都不知道自己在不經意間,將自己項目的源碼“開源了”。

當然,我感覺有很多人搞混淆了,前端打包的意義。以爲之所以要打包,就是爲了加密自己的代碼,防止源碼泄露。但是殊不知,這是一種狹隘的,帶有極度偏見的一種看法。

之所以要打包項目,主要的目的是爲了,壓縮代碼,加快數據的傳輸,減少 http 請求,從而優化前端頁面的性能。

先不說,你寫的代碼是不是真的那麼具有參考價值,“防君子不防小人”真的是一句在很多情況下都極度適合的一句話。

而且,就不說,很多趕工期項目的代碼其實都是所謂的“屎山”,時過境遷以後,自己拿出來看能不能耐心的讀下去都不一定,究竟會有哪個高手願意“抄襲”你的代碼。

不過,對於伸手黨來說,確實能起到很好的防範作用,畢竟也有很多“程序員”都是靠着到處 ctrl + c,ctrl + v 來謀生的。

過程

話不多說,言歸正傳吧。

我們的標題是:react 腳手架打包不生成 sourceMap 的解決方案。

那麼首先說下,爲什麼我需要這個需求。

當然對於我個人的項目而言,我肯定是很樂意加上這個的,畢竟萬一有人想研究我的源碼,sourceMap 說不定能給予一定的幫助呢。

但是對於公司的項目而言,這個功能就不太好了,除非你老闆完全不懂前端,或者他也擁抱開源的世界,否則,還是關掉比較比較合適。

再者,sourceMap 也無形之中增加了打包以後的文件的體積,有時候項目需求就是,輕量級,所以對於這樣的項目而言,sourceMap 就有點多餘了。

當然,這個問題,也不是最近第一次碰到了。

以前用 vue-cli 的時候,也碰到過這個問題了。

不知道是不是因爲 vue 的用戶比較多,還是什麼別的原因。當時我用 vue-cli,第一次想解決這個方案的時候,很容易就搜出了答案。

無非就是在某個打包的配置文件裏面,有個 sourceMap 的屬性,將屬性設置爲 false 就 ok 了,然後這個問題就解決了。

所以當我用 react-cli 的時候,想要關掉這個功能,自然就會去配置文件裏面找了,我的直覺告訴我,應該會有關閉的地方。

果不其然,在根目錄的 config 文件夾內,有個 webpack 的配置文件 webpack.config.js ,往下拉一點,緊接着引模塊後面,就找到了這麼行代碼:

// Source maps are resource heavy and can cause out of memory issue for large source files.
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';

相信,稍微懂點英語的人就能看出來,這就是判斷要不要使用 sourceMap 的參數了。如果結果爲 true,那麼在打包的過程中,就會生成 sourceMap 文件;如果爲 false,肯定就是不生成了。

解決方案

所以此時有幾種方案:

  1. 直接把這句代碼註釋掉,在下面加一行 const shouldUseSourceMap = false
  2. 配置 nodejs 運行時候的環境變量,傳入 GENERATE_SOURCEMAP 值爲 false

但是在這個地方,我第一直覺是,第一種方案其實是有問題的,直接註釋掉判斷語句,不給 sourceMap 固然可行,但是違背了代碼修改的原則。

之所以這麼說是因爲,程序員都知道,對於一個軟件,出 bug 是很正常的。要不然很多人怎麼開玩笑說,上至各種 手機 App、電腦軟件,下至各種手機操作系統安、Windows 系統等,重啓一般能解決百分之九十九的問題。

所以,即使是自己親自參與項目的人來說,都不能保證改了一個地方的代碼,整個項目運行不會出現什麼意料之外的後果。

那麼,對於我們這種項目的“使用者”來說,改代碼將項目改崩了的可能性就更大了。

所以,在修改別人代碼的時候,最好的方式就是按照寫代碼的人的意圖來改是最省事的。

就比如這地方,作者告訴你了,他是通過判斷 process.env.GENERATE_SOURCEMAP 來決定要不要使用 sourceMap 的,那麼我們就在打包的時候,提前將這個環境變量設置爲 false 不久 ok 了麼。

也就是這裏,其實我上面給出第二種方案,是比較好的方案。

當然,這個地方,你即使用了第一種方案,也無傷大雅,最多就是項目打包不生成 sourceMap 而已,其實沒有多大的事兒。

但是你一旦用慣了這種方式,習慣了違背代碼修改的原則,那麼很可能就自己爲自己埋雷了。

指不定,你以後故伎重演的時候,就會在哪裏碰壁了。你無意中加上了一根壓死駱駝的最後一根稻草,卻很難發現,估計也想不起來,到底是哪一根起了這個關鍵性作用。

因爲,我這篇文章想討論的就是我上面提出來的第二種解決方案了——通過環境變量來控制到底要不要生成 sourceMap。

雖然一直在用 nodejs,但是配置環境變量,咱還真的不瞭解。

怎麼辦?

這個時候,對於高端一點的程序員來說,查文檔無疑就是最好的方式了。

哈哈,開個玩笑,其實對於新手程序員來說,碰到問題我還是建議善用搜索引擎的,查文檔雖然好,但是對新手卻不太友好。

新手往往對某個知識點還沒有形成一個體系,他根本不知道自己知道什麼,也不知道自己不知道什麼。

通俗點講,也就是說,他根本發現不了自己想找的問題的關鍵或者說本質到底是什麼。

舉個通俗點的例子,同事某天碰到問題,跑來找我尋求解決方案。他說他明明看了很多遍,根本沒發現代碼寫的有啥問題,也進行了調試,所以一籌莫展,根本不知道自己錯在哪兒了,無論如何就是得不到想要的結果。

這種時候,憑我的經驗,如果是一級菜鳥,很可能是代碼裏面中英文標點符號用錯了;如果是二級菜鳥,很可能是參數類型傳錯了,或者乾脆漏傳參數了;如果是三級菜鳥,…。

所以說,寫代碼就是一個循序漸進不斷加深對一個體系理解的過程。

言歸正傳吧。

碰到問題,首先想到先去查文檔肯定是沒錯的:http://nodejs.cn/api/process.html#process_process_env

上面給出的鏈接,就是 nodejs process 的 api,我們可以看到 env 屬性返回的是包含用戶環境的對象:

![屏幕快照 2019-09-28 09.41.38.png](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9jZG4ubmxhcmsuY29tL3l1cXVlLzAvMjAxOS9wbmcvMjA0OTU0LzE1Njk2MzU3ODcwNDUtMjVhOTczZmQtNThjZS00YmI5LWEyYTEtYWJhNTE4Y2NiMTBjLnBuZw?x-oss-process=image/format,png#align=left&display=inline&height=850&name=屏幕快照 2019-09-28 09.41.38.png&originHeight=850&originWidth=1122&search=&size=114892&status=done&width=1122)

看到這裏,我就以爲自己搞明白了,於是就開始霹靂啪啦的測試了。

首先我想到的是,因爲我項目在打包的時候,直接運行的是 config.json 裏面的 script,也就是直接從命令行進入項目根目錄,然後敲命令 yarn build 開始打包項目。

所以,那麼我是不是就意味着,我直接在命令行運行 GENERATE_SOURCEMAP=false && yarn build 就行了呢?

猜想是沒有用的,需要測試纔行。

於是我打開命令行,開始測試:

E:> GENERATE_SOURCEMAP=false && yarn build
'GENERATE_SOURCEMAP' 不是內部或外部命令,也不是可運行的程序
或批處理文件。

可以看到,在 Windows 的 cmd 下,並不是採用這種方式設置環境變量的,那麼該怎麼用呢?

我努力的回憶了一下,搜尋了一下我本就少的可憐的 Windows bat 腳本經驗,感覺貌似可以通過 set 來設置環境變量。

這個時候,本來應該打開搜索引擎來來查找的,但是出於一個程序員的直覺,咱先調試一下嘛,實在不行再上網搜索嘛。

於是我滿懷期待的改了下命令:

E:> set GENERATE_SOURCEMAP=false && yarn build
yarn run v1.17.3
$ node scripts/build.js
Creating an optimized production build...
Compiled successfully.

File sizes after gzip:

  39.2 KB  build\static\js\2.4236b037.chunk.js
  4.92 KB  build\static\js\main.105aa1c9.chunk.js
  779 B    build\static\js\runtime~main.9affd965.js
  559 B    build\static\css\main.98bee1ae.chunk.css

The project was built assuming it is hosted at ./.
You can control this with the homepage field in your package.json.

The build folder is ready to be deployed.

Find out more about deployment here:

  https://bit.ly/CRA-deploy

Done in 6.63s.

果然我的猜想還是正確的,看來之前的 bat 腳本沒白寫啊。

於是我滿懷期待的打開 build 文件夾,卻發現居然失敗了,還是出來的 map 文件

![屏幕快照 2019-09-28 10.22.17.png](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9jZG4ubmxhcmsuY29tL3l1cXVlLzAvMjAxOS9wbmcvMjA0OTU0LzE1Njk2MzczNTg4NzMtMDI4MzZkOWYtMjUwZC00MGI2LTk3MTItN2Q1MmQzMTQ3NDJmLnBuZw?x-oss-process=image/format,png#align=left&display=inline&height=358&name=屏幕快照 2019-09-28 10.22.17.png&originHeight=358&originWidth=1156&search=&size=200893&status=done&width=1156)

怎麼回事,難道是寫錯了?

我又回過頭去看了下配置裏面的代碼:

// Source maps are resource heavy and can cause out of memory issue for large source files.
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';

難道是要寫成 GENERATE_SOURCEMAP='false' 纔是正確的嗎?

我改了改命令,卻發現還是不行,之後我進行了好幾次嘗試,甚至對代碼進行調試,卻發現始終都不行,shouldUseSourceMap 這個變量怎麼着都是 true,到底哪裏出了問題?

據不完全統計,我嘗試了下面數種寫法:

set GENERATE_SOURCEMAP=false && yarn build
set GENERATE_SOURCEMAP=`false` && yarn build
set GENERATE_SOURCEMAP="false" && yarn build
set GENERATE_SOURCEMAP='false' && yarn build
set GENERATE_SOURCEMAP=false && npm run build
set GENERATE_SOURCEMAP=false && node scripts/build.js

其間還進行了各種組合測試,始終不得其解,甚至配合 vscode 進行調試,還是沒有找到問題所在。

就在我快要抓狂,甚至開始一度懷疑是不是 nodejs 有 bug 的時候,我忽然想起來了,我幹嘛不先在直接用 nodejs repl 測試呢?

於是我打開一個新的 cmd  窗口進行驗證了:

# 第一次測試
E:> set hello=false && node
> process.env.hello
'false '

# 第二次測試
E:> set world='false' && node
> process.env.world
'\'false\' '

這麼一看,頓時感覺自己傻逼了,之所以一直不對,是因爲傳入的變量後面有個多餘的空格。

而且也並不需要寫成字符串格式,因爲本身就是字符串,我又回去仔細的看了下官方文檔,才發現官方文檔裏寫的很清楚了:

![屏幕快照 2019-09-28 10.37.48.png](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9jZG4ubmxhcmsuY29tL3l1cXVlLzAvMjAxOS9wbmcvMjA0OTU0LzE1Njk2MzgzNjM2MzgtZTMyYmE4NDQtNDY1ZC00NzQ1LTk3YTEtOTgyMDVhMmFkMDY2LnBuZw?x-oss-process=image/format,png#align=left&display=inline&height=552&name=屏幕快照 2019-09-28 10.37.48.png&originHeight=552&originWidth=1768&search=&size=94264&status=done&width=1768)

本身就是會將屬性轉爲字符串的,所以 webpack 的配置文件裏面,纔會用 'fasle' 而不是我們的 Boolean 對象 false

// Source maps are resource heavy and can cause out of memory issue for large source files.
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';

// 不是下面這種寫法:
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== false;

所以在 cmd 中,正確的寫法應該是這樣的:

E:> set GENERATE_SOURCEMAP=false&& yarn build

我換用這種寫法,重新打包,果然不再生成 souceMap 文件了。

當然,直接寫在 config.json 裏面是最方便的:

{
  "scripts": {
    "start": "node scripts/start.js",
    "build": "set GENERATE_SOURCEMAP=false&& node scripts/build.js",
    "test": "node scripts/test.js"
  },
}

當然,如果你想在 Linux 的 bash 中用,卻不是這種用法:

$ set a=false && node
> process.env.a
undefined

經我測試,是這種方式:

$ export a=false && node
> process.env.a
'false'

所以如果你想要兼容 Linux 系統下的打包,就朝 config.json 裏面加一條腳本就行了:

{
  "scripts": {
    "start": "node scripts/start.js",
    "build": "set GENERATE_SOURCEMAP=false&& node scripts/build.js",
    "build-linux": "export GENERATE_SOURCEMAP=false && node scripts/build.js",
    "test": "node scripts/test.js"
  },
}

反思

很多時候,折騰了很久,踩了很多坑,到最後才發現是自己之前腦袋秀逗了。

所以解決編程過程中出現的問題,最好的方式就是去查閱官方文檔,並且要仔細閱讀每一個字,可能有的時候忽略的地方,就是解決問題的關鍵所在。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章