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

看到这里,我就以为自己搞明白了,于是就开始霹雳啪啦的测试了。

首先我想到的是,因为我项目在打包的时候,直接运行的是 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

怎么回事,难道是写错了?

我又回过头去看了下配置里面的代码:

// 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

本身就是会将属性转为字符串的,所以 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"
  },
}

反思

很多时候,折腾了很久,踩了很多坑,到最后才发现是自己之前脑袋秀逗了。

所以解决编程过程中出现的问题,最好的方式就是去查阅官方文档,并且要仔细阅读每一个字,可能有的时候忽略的地方,就是解决问题的关键所在。

你可能感兴趣的:(react 脚手架打包不生成 sourceMap 的解决方案)