你不知道的webpack和webpack-dev-server高级玩法
把webpack作为一个node module使用相信很多同学都知道webpack,毕竟是现阶段最火的前端打包工具,现在要是不知道webpack,你可能都不好意思出去面试说你是前端工程师,面试官估计也会斜着眼心里嘀咕:又是个页面仔。webpack的基本用法我想大家应该都知道,你写一个配置文件,然后通过
webpack --config /path/to/your/config.js
启动webpack就可以进行打包,或者通过webpack-dev-server --config /path/to/your/config.js
启动dev-server,你就可以花式使用热更替功能提高你的开发效率了。而我今天就为大家来讲一讲,webpack和webpack-dev-server的一些高级玩法。
大部分情况下,我们都直接命令行启动webpack进行打包,就可以满足我们的需求。但毕竟计划赶不上变化,有时候你会发现用命令行启动webpack变得不是那么方便。比如我们在调试react的服务端渲染的时候,我们不可能每次有文件更新,等着webpack打包完输出到硬盘上某个文件,然后你重启服务度去加载这个新的文件,因为这太浪费时间了,毕竟开发时你随时都可能改代码,而且改动可能还很小。
那么要解决这个问题怎么办呢?我们可以在启动nodejs服务的时候,顺带启动webpack打包服务,这样我们可以在nodejs的执行环境中拿到webpack打包的上下文,就可以不重启服务但每次文件更新都可以拿到最新的bundle。那么具体怎么做呢?很简单,看下面的代码:
const webpack = require('webpack')
const webpackConfig = require('/path/to/your/config.js')
const compiler = webpack(webpackConfig)
compiler.run((err, stats) => {/* ...处理结果 */})
// or
compiler.watch({
// watch options
}, (err, stats) => {/* ...处理结果 */})
通过给webpack传入配置,可以得到一个webpack的compiler,你可以调用compiler.run
来一次性调用webpack的打包服务,他接受一个callback方法,你可以在里面处理他的打包结果。
同时你也可以调用compiler.watch
来让webpack监听文件变化,每次更新打包结束都会调用你传入的callback。而第一个参数是watchOptions,跟配置文件里面的watchOptions是一样的。
但是这样做了之后呢,webpack依旧是把文件打包到本地磁盘,显然在开发的时候我们并没有这个需求,我希望的是提高打包速度,而写入磁盘明显是个低效率的操作,我们要避免这个问题。怎么做呢?还在webpack为我们提供了一个配置项,我们可以指定webpack输出的文件系统。
const MemoryFS = require('memory-fs')
const mfs = new MemoryFS()
compiler.outputFileSystem = mfs
memory-fs是一个在内存中存储读取文件的文件系统类库,他的api和nodejs默认的fs一模一样,所以直接给compiler.outputFileSystem
之后,所有webpack输出的文件都将存储在内存里面。而随后,我们都可以通过mfs对象,读取到这些文件。速度瞬间上了一个档次有木有。其实webpack-dev-server内部也用了这个方法,他才能快速得帮我们更新代码。
同样的道理,我们有时候也需要在nodejs在启动webpack-dev-server,而webpack-dev-server和webpack不同的是,他本身自己也会启动一个服务,并监听独立的端口。但是我们也有办法让他不这么做,我们可以让只启动我们自己的服务,但同时可以具备webpack-dev-server那些牛逼的功能,怎么做呢?
我们要用两个工具:webpack-dev-middleware
和webpack-hot-middleware
,这两个是express的中间件,如果你的服务使用express开发的,那么你可以很方便的把这两个工具集成到你的服务上,我们来看看怎么做:
const express = require('express')
const devMiddleware = require('webpack-dev-middleware')
const hotMiddleware = require('webpack-hot-middleware')
const app = express()
app.use(devMiddleware(compiler, {/* dev config */}))
app.use(hotMiddleware(compiler))
// ...your server code here
这里的compiler就是我们上面webpack生成的compiler,devMiddleware的config跟webpack配置里面的devServer
的配置基本类似,但是也有几个不一样的配置,具体可以移步这里查看详细api
但是这样还不能实现热更替功能,在使用hotMiddleware的时候,我们需要在我们webpack配置的entry中加入一个文件webpack-hot-middleware/client
,这是一共在客户端跟hotMiddleware进行通信的js,有了它之后,我们客户端才能接收到新的代码并覆盖老的代码。
你以为这样就结束了吗?还有呢
虽然通过上面的方式我们可以只起一个服务,但是这也有弊端,就是webpack的打包服务要随着我们重启node服务而重启,而总所周知,如果你的前端应用很复杂,那么webpack打包的速度会很慢,重启webpack的成本还是很高的,如果你经常要改服务端的代码,那这就不划算了。那有没有办法能把这两个服务分开,但又是在node中启动呢?
答案当然是有的,只要你有需求,没有你解决不了的问题,前提是你敢想敢做
const WebpackDevServer = require('webpack-dev-server')
const devServer = new WebpackDevServer(compiler, {/* devServer config */})
devServer.listen(/* port */)
这样子你就可以通过nodejs启动webpack-dev-server了
这是在webpack-dev-server的文档中没有提到的,其实他也是可以直接作为一个node module使用的。
当然如果你的express server和dev server都写在一个js入口文件中启动,那么你每次修改服务端代码,还是顺便会重启dev server。这时候如果你要区分,可以把这两个入口文件分开,然后在一个脚本中通过child_process
分别启动两个服务,然后在这个脚本中控制这两个服务什么时候该重启,这一块我就不深入讲了,大家可以自己去研究一下,只要知道了上面这些方法,你就可以随意控制你的服务在何时启动,又在何时结束。
以上就是webpack和webpack-dev-server的一些高级玩法,当然我这里只是抛砖引玉,webpack太过复杂,如果要把每个细节写清楚估计能写很厚一本书。写这篇文章的用意更多是希望大家能抛开很多流水线化的编程习惯,去拥抱变化,每一个强大的工具或者框架总有各种等着你去挖掘的用法,你只有往深入去研究,才能解锁更多姿势。
共同学习,写下你的评论
评论加载中...
作者其他优质文章