这是我参与更文挑战的第9天,活动详情查看: 更文挑战
有些事webpack真不好办
如此强大的webpack
,有什么能难住ta?
在解答这个问题之前,我们介绍一些比较“冷”的知识
assets和public
项目会有很多的静态资源,理论上讲放在这俩文件下都能运行项目,但是有很大区别。
简单讲
- assets:放在这的静态资源会经
webpack
处理,会经过打包优化加上内容hash等一系列美滋滋的加工。 - public:以上都不能,尤其内容hash这块,你会为版本问题提心吊胆。
有些时候有些事情可以简单讲,但这里有必要“费劲”讲讲。
费劲讲
首先我们溯源,通过create-react-app
上的官网看关于public
文件夹的介绍,就能了解一二。
官方鼓励把静态资源放在assets
。
原文在这:
Note that we normally encourage you to import assets in JavaScript files instead
然后列出了三点优势:
- 文件经过压缩尽可能的捆在一起了,文件数少了,自然请求就少,优化了性能。
- 缺少文件,直接就会在
webpack
编译时就报错,这就很安全了。 - 文件都打上了内容hash,不用为版本缓存问题发愁,美滋滋啊,简直太好了。
原文在这:
- Scripts and stylesheets get minified and bundled together to avoid extra network requests.
- Missing files cause compilation errors instead of 404 errors for your users.
- Result filenames include content hashes so you don’t need to worry about browsers caching their old versions.
那么用pubclic呢,会有什么结果呢。
首先官网特别不推荐,并且ta说放在这里的资源并不会被webpack
处理。
原文在这:
If you put a file into the public folder, it will not be processed by webpack.
同时使用资源的时候必须要带着PUBLIC_URL
这个变量当前缀(上一篇讲electron
文章里面已经贴出了解决办法)
原文在这:
Only files inside the public folder will be accessible by %PUBLIC_URL% prefix.
然后的ta的缺点都是放在assets
的优点的反面。
原文在这:
- None of the files in public folder get post-processed or minified.
- Missing files will not be called at compilation time, and will cause 404 errors for your users.
- Result filenames won’t include content hashes so you’ll need to add query arguments or rename them every time they change.
什么时候用呢?
官网给出的策略是:
- 当你用
manifest.webmanifest
这类的特定名称的文件(dllplugin会有涉及,有兴趣可以了解一下) - 你有非常多的图片要动态的使用。
- 你需要引入一些脚本在项目之外
- 你需要引入的一些库,其无法被
webpack
接受
原文在这:
- You need a file with a specific name in the build output, such as manifest.webmanifest.
- You have thousands of images and need to dynamically reference their paths.
- You want to include a small script like pace.js outside of the bundled code.
- Some libraries may be incompatible with webpack and you have no other option but to include it as a
<script>
tag.
那么综上所述,我接下来要解决的问题就符合了上面的第四点,无法被webpack
接受?。
我要解决什么问题
我要解决的问题其实很简单,就是把一个游戏?集成进到我的脚手架中来(集成的办法以后我会单独写文章讲),那么遇到的瓶颈是什么呢?
遇到的瓶颈
瓶颈就是游戏?项目并不被webpack接受,无法放在assets
中,我就只好放在public
中,那么就会有个问题,我无论是否需不需要该功能,都会把游戏包拷贝到项目中。。。。。这就尴尬了,应该按需加载啊,所以这是无法接受的,必须解决。
怎么解决尴尬
那么就是我不尴尬?,尴尬的就是别人,开玩笑,开玩笑,同学请把刀收起来,我必须要去解决,但解决的办法已经不能在webpack
上使劲了,因为ta真的爱莫能助,都没到ta那,不好伸手的,怎么办呢?
这个时候就想起了gulp
gulp是啥,用官方的话说
gulp 将开发流程中让人痛苦或耗时的任务自动化,从而减少你所浪费的时间、创造更大价值
em~~~定位很清晰,排解苦闷用的。
安装
安装 gulp,作为开发时依赖项
yarn add -D gulp-cli
//或
npm install -D gulp gulp-cli
复制代码
安装 gulp 命令行工具
yarn add -g gulp-cli
//或
npm install -g gulp-cli
复制代码
配置gulp
在项目根目录下,创建文件gulpfile.js
,其在运行 gulp
命令时会被自动加载,在这个文件中我们写一下gulp的任务task
。
任务task
任务主要分为两种:
- 公开任务(Public tasks) 从 gulpfile 中被导出(export),可以通过 gulp 命令直接调用。
- 私有任务(Private tasks) 被设计为在内部使用,通常作为 series() 或 parallel() 组合的组成部分。
任务的执行有可以分同步和异步:
- series是同步,如
series(task1,task2, task3)
- parallel是异步,如
parallel(task1,task2, task3)
先贴出本文相关代码,然后再分析:
/* gulpfile.js */
...
var del = require('del');
function cleanGame(cb) {
return del([
'build/web-mobile',
]).then(() => {
cb()
process.exit();
});
}
...
exports.cleanGame = cleanGame;
...
复制代码
分析
该方式并没有借助插件,官网推荐就是只有在转换文件时用插件,其他操作都应该使用(非插件的) Node
模块或库。
原文如下:
Plugins should always transform files. Use a (non-plugin) Node module or library for any other operations.
这里强调一点,这里引入的del
可不是Node
的模块,ta是库,但是你并不用手动安装ta。
为什么?
别问,问就是我徒手一点一点分析依赖找出来的?。
我从一堆依赖中,翻找出的关键信息如下:
...
webpack-dev-server:
...
dependencies:
...
del "^4.1.1"
...
...
复制代码
webpack-dev-server
已经自带了这个依赖,所以也就不用手动安装就可以引入了,可别错误的认为是Node
模块奥。
del
库使用上也很简单,传入一个数组,其放入匹配的path,或是文件或是文件夹都行,可以动手试一下,然后ta会被返回一个Promise
实例。你可以通过.then
的方式去执行回调,其中回调函数中分别执行了两个函数:
cb()
:由于我们并没有返回一个stream
流,所以我们需要手动的执行这个传入cb
,以告知整个gulp流程该处理已经结束。可以看下stackoverflow的问题,其中这一段说的就很清楚:
By returning a stream, the task system is able to plan the execution of those streams. But sometimes, especially when you’re in callback hell or calling some streamless plugin, you aren’t able to return a stream. That’s what the callback is for. To let the task system know that you’re finished and to move on to the next call in the execution chain.
process.exit();
退出命令进程,exit
的参数是code
不传默认为0,表示成功,执行这句话,就是希望能够结束的时候自动的退出进程,省的我手动结束终端?。
这里必须强调:ta俩执行顺序不能反了,要不会报错的。
[08:32:38] The following tasks did not complete: cleanGame
[08:32:38] Did you forget to signal async completion?
复制代码
配置启动脚本
执行的命令很简单,直接执行:
gulp cleanGame
复制代码
然后在package.json
中配置一下脚本命令,方便使用和集成。
"scripts": {
...
"cleanGame": "gulp cleanGame",
...
}
复制代码
至此gulp
的基本配置ok了?,通过该命令就能直接的讲游戏包?在打包之后去掉,而gulp如何做到整合命令,优雅的全自动化,我觉得有必要单独的写一篇,好好说说。
结语
gulp
往往会在wabpack
不方便的情况给予帮助,二者高低搭配,也恰恰呼应了Moderate
的主张,中庸兼容,保中守和。