从0到1使用Webpack5 + React + TS构建标准化应用

网站建设4年前发布
37 0 0

作者 | 刘皇逊(恪语,本篇文章主要讲解如何从一个空目录开始,建立起一个基于webpack + react + typescript的标准化前端应用。,在项目开发中,我们可以使用create-react-app或者飞冰等脚手架工具,那么,为什么我们要自己来搭建一个标准化项目?,首先从一个空目录开始,对项目初始化:,对于一个React项目,我们首先要安装React,写一个Hello World!安装我们主要的项目依赖:,由于我们的浏览器不支持最新的ECMAScript语法,所以我们需要Babel来转义为ES5或者ES6。安装我们的Babel来提高兼容性:,.babelrc中添加基本配置:,Babel是代码转换器,借助Babel,我们可以使用最流行的js写法,而plugin就是实现Babel功能的核心。,20230306015345d267ec19831bd50ba95627b3f1b3dd5f325a2b982,这里的配置是为了支持react中class的写法。,Babel的Plugin一般拆成尽可能小的粒度,开发者可以按需引进,例如ES6到ES5的功能,官方提供了20+插件,这样可以提高性能和扩展性,但是很多时候逐个引入就很让人头大,而Babel Preset就是为此而生,可以视为Presets是相关Plugins的集合。,新建一个webpack.config.js文件。,目前的项目结构如下图所示:,20230306095548c6bda49601e90de42e162673f252b063868846564,js和html文件如下图所示:,最后,只要start一下,项目就会启动在8080端口。,同时在根目录加入tsconfig.json来对ts编译进行配置:,最后在webpack中添加对ts的支持。,最后启动一下server来看一下ts配置是否正确。,20230306015346355c9c298979ff5696514020bcd0972ee795ab804,上述我们的配置其实相当于执行了一次:,在这种流程下很是麻烦,将 *.ts 提供给 TypeScript,然后将运行的结果提供给 Babel,而且还要借助很多loader。,20230306095549372cfd7822045a0cd96556deabbe6849464ba1440,那么我们能不能简化一下这样的流程,因为Babel7中提供的babel-loader就可以完美进行编译ts,答案是可以的,这种方式直接简化了过程。,20230306015347924a37e50a46e473c628061e10cf3427a19e12471,并且在.babelrc中也只多了一行@babel/preset-typescript,这种配置更简单,而且打包速度更快一点,逻辑更加清晰。那么为什么还要在项目中使用ts-loader呢?,webpack 只能理解 JavaScript 和 JSON 文件,这是 webpack 开箱可用的自带能力。loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效的模块中。loader中,test属性可以识别出哪些文件会被转换;use属性可以定义出转换时,应该是用哪个loader。,安装loader:,webpack配置:,对于图片和字体,我们可以使用内置的Assets Modules来轻松地把这些内容加到我们的系统中,对于类型,我们可以选择:,对于其他类型资源,我们需要安装csv-loader、xml-loader等:,目前,我们的应用已经可以正常运行tsx文件,并且在本地进行调试和开发,那么我们来看看如何设置一个开发环境,来使开发变得更加轻松。,我们可以从process.env中获取环境变量来区分开发环境和生产环境。当webpack在本地打包代码时,我们可以使用inline-source-map,可以将编译后的代码映射回原始源代码,这样在报错的时候,错误就会被定为到确切的文件和行数。当然,在生产环境中,为了保护隐私,最好把这个设置动态关掉。在开发环境中,webpack-dev-server会为你提供一个基本的web server,并且具有实时重新加载功能。,我们希望每次打包都把上次的打包文件删除,可以使用CleanWebpackPlugin:,并且,在我们生产环境,我们希望改动后的新版本可以丢弃缓存,并且没有改动的版本可以保留缓存;但是在开发环境,我们不希望有缓存,而是每次都是拿到最新的资源。所以,需要对webpack config做一次拆分:分成,里面的区别主要在于打包后的文件名称、sourceMap等。,contenthash:只有模块的内容改变,才会改变hash值:,可以使用webpack-bundle-analyzer来分析我们打包资源的大小:,同时设置package.json的启动项,OptimizeCSSAssetsPlugin主要用来优化css文件的输出,包括摈弃重复的样式定义、砍掉样式规则中多余的参数、移除不需要的浏览器前缀等。TerserPlugin主要用来优化js体积,包括重命名变量,甚至是删除整个的访问不到的代码块。,资源分离,webpack内置的特性能够把代码分离到不同的bundle 中,然后可以按需加载或并行加载这些文件。代码分离可以用于获取更小的bundle,以及控制资源加载优先级,如果使用合理,会极大影响加载时间。,Webpack5在生产环境已经集成了Tree Shaking功能,不用的代码会被shaking掉:,但是在开发环境中需要手动配置(Not Recommend):,处于好奇,webpack是如何完美的避开没有使用的代码的呢?很简单:就是 Webpack 没看到你使用的代码。Webpack 跟踪整个应用程序的import/export 语句,因此,如果它看到导入的东西最终没有被使用,它会认为那是未引用代码(或叫做“死代码”—— dead-code ),并会对其进行 tree-shaking 。死代码并不总是那么明确的。下面是一些例子:,所以对于这种三方库我们可以使用下面的Shimming方法。注意 Webpack 不能百分百安全地进行 tree-shaking。有些模块导入,只要被引入,就会对应用程序产生重要影响。一个很好的例子就是全局样式表,或者设置全局配置的JavaScript 文件。Webpack 认为这样的文件有“副作用”。具有副作用的文件不应该做 tree-shaking,因为这将破坏整个应用。比较好的告诉Webpack你的代码有副作用的方法就是在package.json里面设置sideEffects。,对于上面的lodash库无法被shaking,我们可以使用细粒度shimming预置的方法来优化,首先引入ProvidePlugin插件,把应用程序中的模块依赖,改为一个全局变量依赖,让我们先移除 lodash 的 import语句,改为通过插件提供它,并且提取出join方法来全局使用它:,细粒度Shimming,一些遗留的模块依赖的this指向的window对象,我们可以使用import-loaders,它对依赖 window 对象下的全局变量(比如 $ 或 this )的第三方模块非常有用。CommonJS 上下文中,这将会变成一个问题,也就是说此时的 this指向的是 module.exports。在这种情况下,你可以通过使用 imports-loader覆盖 this 指向:,防止重复可以使用splitChunk,提取出代码中的公共部分:,minSize:形成一个新代码块最小的体积,cacheGroups:这里开始设置缓存的 chunks,在React项目中,代码按需分离可以使用如下方法,webpack 把 import() 作为一个分离点(split-point),并把引入的模块作为一个单独的 chunk。import() 将模块名字作为参数并返回一个 Promoise 对象,即 import(name) -> Promise。,配置 dependOn option 选项,这样可以在多个 chunk 之间共享模块:,CSS分离,该插件MiniCssExtractPlugin将CSS提取到单独的文件中。它为每个包含CSS的JS文件创建一个CSS文件。,当项目体积增大时,编译时间也随之增加。其中时间大头就是ts的类型检测耗时。ts-loader 提供了一个 transpileOnly 选项,它默认为 false,我们可以把它设置为 true,这样项目编译时就不会进行类型检查,也不会输出声明文件。,可以看一下开关这个选项后的前后对比:开启检查前;,关闭检查后;,From 4.88s --> 2.4s,但是缺少了类型检查。这里官方推荐了一个解决方案,使用fork-ts-checker-webpack-plugin,它在一个单独的进程上运行类型检查器,此插件使用 TypeScript 而不是 webpack 的模块解析,有了 TypeScript 的模块解析,我们不必等待webpack 编译。可以极大加快编译速度。,在根目录新建.editorconfig即可,注意不要与已有的lint规则冲突:,babel中配置按需加载:,webpack中定制主题:,注意样式必须加载 less 格式,一个常见的问题就是引入了多份样式,less 的样式被 css 的样式覆盖了。,ESlint主要功能包含代码格式和代码质量的校验,并且可以配置pre-commit来规范代码的提交。,ESlint配置文件:,虽然 ESLint 也可以校验代码格式,但 Prettier 更擅长,所以项目中一般会搭配一起使用。为了避免二者的冲突,一般的解决思路是禁掉 ESLint 中与 Prettier 冲突的规则,然后使用 Prettier 做格式化, ESLint 做代码校验。prettier配置文件,prettier 只是保证了在通过编辑器(vs code)进行格式化代码的时候,格式化成需要的格式(当然可以通过配置 onSave 在代码保存时自动格式化),但是无法保证所有人都会主动进行。因此进行自动格式化显得非常重要,而自动格式化的是时机选择 pre-commit 最恰当,通过 git hook ,能够在 commit 之前格式化好代码(如果已经 commit,会将暂存转为提交,生成提交记录,需要回滚才会撤销)。,package.json设置;,最后贴一下完整的配置,因为Aone发布自动更新版本号,所以不用拆分config文件来根据环境设置缓存,并且配置已经尽可能简化,拆分反而会增加维护成本。,这篇文章主要记录了开发过程中从项目初始化开始,再到一个标准化前端项目的搭建路程。涉及相关代码规范、开发环境搭建、生产环境优化等,旨在打造出一个可快速使用的现代Webpack5.x+React18.x+Typescript+Antd4.x模板,以供在以后的实际业务场景需求中零成本使用。

© 版权声明

相关文章