26、前端知识点--利用webpack搭建脚手架一套完整流程

前言

我们的目标是利用webpack搭建一个基于react + react-router +dva + es6 + less + antd用于中后台开发的脚手架,同学们可能会说社区里那么多优秀的脚手架为什么还要自己搭,而且网络上这类文章也非常的多,没有再重复写的必要,但是对我而言,分享也是再次学习的过程,只有自己动手实现一遍才会使印象更加深刻,总的来说基本秉持一个理念:在学习中分享,在分享中学习。

初始化项目

新建index.js和index.html文件:

安装webpack并配置

安装webpack

新建一个build文件夹存放wbepack配置文件

webpack.dev.js,并书写基本的配置(https://github.com/LuoShengMen/React-Whole-barrels/commit/c39b7e9fb67326d0afdda408a600f0a88beca946)

package.json更改

配置babel

既然要使用react和es6,babel的配置是必不可少的

扩展:如果是开发工具库,想要实现按需替换,可以使用下面下面两个工具来实现

@babel/plugin-transform-runtime避免 polyfill 污染全局变量,减小打包体积,因此更适合作为开发工具库

@babel/runtime-corejs2作为生产环境依赖,约等于@babel/runtime + babel-polyfill,使用了@babel/runtime-corejs2,就无需再使用@babel/runtime了

.babelrc文件

1.解决:Support for the experimental syntax \'classProperties\' isn\'t currently enabled 问题,

npm i -D @babel/plugin-proposal-class-properties,并在plugins中配置。

2.useBuiltIns 和 transform-runtime 不能同时使用,如果使用transform-runtime就不要配useBuiltInsor,一般独立的类库项目才用transform-runtime,出处(https://segmentfault.com/q/1010000018937075/)

更改webpack.dev.js

安装react

安装react、react-dom、react-router,并书写代码

这部分代码较多,可以在github上查看src的代码(https://github.com/LuoShengMen/React-Whole-barrels/commit/55a0a0efdf5f581886a303326259fa9b2ff88444)

webpack-dev-server

书写完成上述代码运行npm start后,打开index.html你会发现没有任何内容,此时我们需要配置一个简单的WEB服务器,指向index.html。

运行npm start命令,既可以看到我们的代码内容。dev更多配置请看这里(https://github.com/LuoShengMen/StudyNotes/issues/535)

使用html-webpack-plugin和clean-webpack-plugin插件

到目前为止,我们会发现都需要手动都将index.html放到dist文件夹中,并手动引入bundle.js.这个问题可以通过html-webpack-plugin解决。

引入html-webpack-plugin后,在plugins生成一个实例,HtmlWebpackPlugin可以接受一个参数作为模版文件,打包结束后自动生成一个以参数为模版的html文件。并把打包生成的js文件自动引入到html文件中。clean-webpack-plugin可以实现在每次打包之前都把上一次的打包文件清空,这样避免了冗余文件的存在,用法也是直接在plugins里面生成一个实例.

更改webpack.dev.js

less配置

样式使用less预处理器,那么就需要使用less,less-loader,css-loader,style-loader等

更改webpack.dev.js配置

postcss.config.js

图标和图片的处理

安装file-loader和url-loader

filr-loader帮助我们做两件事情:

1.当遇到图片文件时会将其打包移动到dist目录下

2.接下来会获得图片模块的地址,并将地址返回到引入模块到变量之中

url-loader基本上可以实现file-loader的功能,但是有一区别就是经过url-laoder打包后的dist文件下是不存在image文件的,这是因为url-loader会把图片转换成base64的字符串直接放在bundle.js里面。

好处:直接将图片打包到js里,不用额外到请求图片,省了http请求

坏处:如果遇到打包到文件非常大,那么加载会加载很长时间,影响体验

因此我们可以这样配置webpack.dev.js

模块热替换HMR

模块热替换也称为HMR,代码更新时只会更新被修改部分都显示。有如下有点

  • 针对于样式调试更加方便

  • 只会更新被修改代码的那部分显示,提升开发效率

  • 保留在完全重新加载页面时丢失的应用程序状态。

HMR配置有两种方式,一种cli方式,一种Node.js API方式,我们这里采用第二种方式,如果想了解两种HMR的实现以及HMR实现原理可以看这里((https://github.com/LuoShengMen/StudyNotes/issues/492))。

我们通过在自定义开发服务下,使用插件webpack-dev-middleware和webpack-hot-middleware配合实现HMR

新建dev-server.js

更改webpack.dev.js,添加如下内容:

webpack-hot-middleware更多配置在这里(https://github.com/LuoShengMen/StudyNotes/issues/492)

修改启动命令:

安装antd和dva

安装antd后即可使用and-design里面的ui组件。使用babel-plugin-import来实现按需加载的效果

.babelrc

成功安装后改写index.js和并新建router.js

这里的代码量有点多就不一一列出,可以在github上面查看(https://github.com/LuoShengMen/React-Whole-barrels/commit/4dd8a5866760a2727acc95854cc6ab80b48d845d)

在使用react-router的过程中你可能会出现这样的问题,点击刷新后报错 or Cannot GET,解决方案有两个。

1.用的 BrowserRouter 改为 HashRouter 即可。2.devServer 中必须设置 historyApiFallback: true

由于我们使用的自定义服务,那么我们可以使用connect-history-api-fallback来实现和historyApiFallback相同的功能。具体实现看代码(https://github.com/LuoShengMen/React-Whole-barrels/commit/5b3c332136b852ac836dfe2da2c647bf96315911)

public path

CDN通过将资源部署到世界各地,使得用户可以就近访问资源,加快访问速度。如果我们把网页的静态资源上传到CDN服务上,在访问这些资源时,publicPath填写的就是CDN提供URL

我们当前用/,相对于当前路径,是因为我们的资源在同一文件夹下。》》

webpack.dev.js

使用sourcemap

sourceMap本质上是一种映射关系,打包出来的js文件中的代码可以映射到代码文件的具体位置,这种映射关系会帮助我们直接找到在源代码中的错误。可以直接在devtool中使用.合理的使用source-map可以帮助我们提高开发效率,更快的定位到错误位置。

生产环境和开发环境的devtool配置是不同的。我们可以在webpack.dev.js中添加devtool。

生产环境构建

到目前为止我们配置的都是开发环境的webpack,开发环境(development)和生产环境(production)的构建目标差异很大,而在生产环境中,我们的目标则转向于关注更小的 bundle,更轻量的 source map,以及更优化的资源,以改善加载时间.

新建webpack.prod.js

添加打包脚本,

执行npm run build后,你会发现dist文件夹下已经生成一系列文件。你会发现生产环境下的配置和开发环境下的配置有很多相同,接下来我们会对webpack配置进行优化。

提取公共配置

webpack.dev.js和webpack.prod.js中有很多相同对配置,我们可以将公共配置提取出来,再使用webpack-merge来将不同环境下的配置合并起来。

webpack配置文件更改

webpack.dev.js

webpack.prod.js

webpack.common.js

具体的可以看这里。(https://github.com/LuoShengMen/React-Whole-barrels/commit/b1412d2debdcbd6f61819f33b2969e39014c5bb2)

CSS文件代码分割

想要分开打包我们的css文件,需要使用mini-css-extract-plugin这个插件,但是这个插件目前还不支持HMR,为了不影响开发效率,因此就在生成环境下使用该插件。

optimize-css-assets-webpack-plugin 这个插件可以帮助我们把相同的样式合并。

css-split-webpack-plugin插件可以帮我们把过大的css文件拆分

修改webpack.prod.js,并同步修改webpack.common.js、webpack.dev.js 看这里

浏览器缓存(Cathing)

为了解决浏览器文件缓存问题,例如:代码更新后,文件名称未改变,浏览器非强制刷新后,浏览器去请求文件时认为文件名称未改变而直接从缓存中读取不去重新请求。我们可以在webpack.prod.js输出文件名称中添加hash值.

使用HashedModuleIdsPlugin的原因是可以当更改某一个文件时,只改变这一个文件的hash值,而不是所有的文件都改变。

运行npm run build命令后,会发现dist文件中js文件名中已经有了hash值

记得同步修改webpack.common.js、webpack.dev.js,如果你不知道如何修改,请看这里(https://github.com/LuoShengMen/React-Whole-barrels/commit/e846c1380d142332e7859a0bb1120ad6a053fd17)

文件路径优化

extension配置之后可以不用在require或是import的时候加文件扩展名,会依次尝试添加扩展名进行匹配

mainFiles配置后不用加入文件名,会依次尝试添加的文件名进行匹配

alias通过配置别名可以加快webpack查找模块的速度。

webpack.common.js更改:

Tree Shaking

Tree Shaking可以剔除掉一个文件中未被引用掉部分,并且只支持ES Modules模块的引入方式,不支持CommonJS的引入方式。原因:ES Modules是静态引入的方式,CommonJS是动态的引入方式,Tree Shaking只支持静态引入方式。

注意:mode 选项设置为 production,可以自动启用 minification(代码压缩) 和 tree shaking

代码分割(SplitChunksPlugin)

不管是同步代码的分割还是异步的代码分割都可以使用SplitChunksPlugin这个插件,可以将第三方库从业务代码中分割出来.

webpack.prod.js

DellPlugin提升打包速度

对于第三方库,这些库在很长的一段时间内,基本不会更新,打包的时候分开打包来提升打包速度, DllPlugin动态链接库插件,其原理就是把网页依赖的基础模块抽离出来打包到dll文件中,当需要导入的模块存在于某个dll中时,这个模块不再被打包,而是去dll中获取。

新建webpack.dll.js

webpack.common.js更改

package.json

PWA优化

PWA全称progressive Web Application,PWA实现的功能是即便服务器挂掉,还是可以通过在本地的缓存来访问到页面。首先安装workbox-webpack-plugin插件,然后在webpack.prod.js中Plugins中配置,因为该功能只在线上使用。

webpack.prod.js更改

运行命令打包后会多处两个文件precache-manifest.js和service-worker.js, service-worker这个文件就可以让我们的页面被缓存住

指定环境

可以通过指定环境,来使webpack进行选择性编译,择性编译是指根据打包是环境的不同,选择性地让特定的语句有效,让特定的语句无效。这样可以对具体用户的环境进行代码优化,从而删除或添加一些重要代码。

最简单的例子,在开发环境中,我们打印日志,但在生产环境中,我们让所有打印日志的语句无效(让程序不运行打印的语句,甚至让打包出来的文件根本就不包含打印日志的语句)

我们可以使用 webpack 内置的 DefinePlugin 来实现。

总结

写到这里,这样一个基本的脚手架也就搭起来了,本文所有代码React-Whole-barrels(https://github.com/LuoShengMen/React-Whole-barrels)都在这里了。大家可以跟着代码进行配置,每一步基本都有commit,如果不清楚可以看commit。当然本文也有许多不完善的地方,例如mock、eslint、styleLint、ts等等都没有添加上去,而且也还有许多优化点,由于篇幅关系我也就不一一写了,后续我会加上以及不断完善优化该项目,感兴趣的同学可以持续关注哦!

希望可以通过本文让您对webpack工具有一个更加深入和全面的认识,以便于应对以后项目中配置更改。如果要使用项目框架的话当热是推荐creat-react-app或者umi了。

本文如果有错误的地方,您发现了,欢迎告诉我!!谢谢!!如果觉得对您有帮助,欢迎给我一个star! ! 谢谢!!