当前位置 博文首页 > 前端开发博客:Webpack5 搭建 Vue3 + TS 项目
点击关注下方卡片关注我????????
回复“Vue3”查阅?Vue3精选文章
各位小伙伴,我回广州了,今天开始更新了。
笔者两年前曾写过一篇文章《Webpack4 搭建 Vue 项目》,后来随着 webpack5 和 vue3 的面世,一直想升级下我这个 createVue 项目,但是苦于没有时间(其实是因为懒),一直拖延至今。捣鼓了好几天,终于搭建好整个项目,因此仅以此文记录升级搭建的过程。
PS: 其实也可以用官方脚手架搭建的,为何要自己从头做起呢?有脚手架我不用,我就折腾。哎,就是玩儿~????
为何升级?除了折腾外,便是享受新版本带给我们的新特性体验。
Webpack5 的新特性
持久化缓存
moduleIds & chunkIds 的优化
更智能的 tree shaking
Module Federation
...
更小
更快
加强 TypeScript 支持
加强 API 设计一致性
提高自身可维护性
开放更多底层功能
编程语言:TypeScript 4.2.4
构建工具:[Webpack 5.33.2]()
前端框架:Vue 3.0.11
路由工具:Vue Router 4.0.6
状态管理:Vuex 4.0.0
CSS 预编译:Sass / Less
HTTP 工具:Axios
Git Hook 工具:Husky + Lint-staged
代码规范:EditorConfig + Prettier + ESLint
提交规范:Commitlint
构建部署:Travis
此文并不是从零搭建,而是在?createVue@v1.0.0?的基础上修改搭建,如若看不懂,可以先看《Webpack4 搭建 Vue 项目》,跟着一步步搭建,后再看此文升级
创建 createVue 文件夹,进入该文件夹, npm init 初始化项目
老规矩,安装 webpack 四件套npm i webpack webpack-cli webpack-dev-server webpack-merge --save-dev
当前使用版本:
"webpack":?"^5.33.2",
"webpack-bundle-analyzer":?"^4.4.1",
"webpack-cli":?"^4.6.0",
"webpack-dev-server":?"^3.11.2",
"webpack-merge":?"^5.7.3",
webpack5 启动开发服务器命令与之前有所变化,从?webpack-dev-server
?转变为?webpack serve
, 因此 package.json 中 script 的 start 修改为:?"start": "webpack serve --progress --hot --inline --config build/webpack.dev.js"
创建相应文件
与之前没有太大差异。增加变动的有一下几点:
1). 持久化缓存,增加 cache 配置. v5 中缓存默认是 memory,修改设置"filesystem"写入硬盘
//?webpack.dev.js
module.exports?=?merge(common,?{
??cache:?{
????type:?'filesystem',
??}
??//...
}
2). 去除插件 clean-webpack-plugin(v5支持),webpack.HashedModuleIdsPlugin(v5更好的 moduleIds & chunkIds),HardSourceWebpackPlugin(v5支持),happypack(v5不兼容)
安装 vue 核心解析插件
解析插件有所不同,从?vue-template-compiler
?变成了?@vue/compiler-sfc
,?vue-loader
?保持不变。?npm i vue-loader @vue/compiler-sfc --save-dev
//?当前我使用版本
"vue-loader":?"^16.2.0",
"@vue/compiler-sfc":?"^3.0.11",
安装 vue3 及相关库,添加 vue 类型文件
npm i vue@next vuex@4.0.0-rc.1 vue-router --save
src 文件夹下添加 shims-vue.d.ts 文件,解决 vue 类型报错
//?shims-vue.d.ts
declare?module?'*.vue'?{
??import?type?{?DefineComponent?}?from?'vue'
??const?component:?DefineComponent<{},?{},?any>
??export?default?component
}
安装 html 模板解析插件
npm i html-webpack-plugin --save-dev
安装 typescript 及解析插件
npm i typescript ts-loader --save-dev
配置ts-loader解析:
//?webpack.base.js
//?rules
{
????test:?/\.(t|j)s$/,
????exclude:?/node_modules/,
????use:?[
??????{
????????loader:?'ts-loader',
????????options:?{
??????????//?指定特定的ts编译配置,为了区分脚本的ts配置
??????????configFile:?path.resolve(__dirname,?'../tsconfig.loader.json'),
??????????//?对应文件添加个.ts或.tsx后缀
??????????appendTsSuffixTo:?[/\.vue$/],
????????},
??????},
????],
}
ts-loader 为单进程执行类型检查和转译,因此效率有些慢,可以用多进程方案:即关闭ts-loader的类型检查,类型检查由?fork-ts-checker-webpack-plugin
?插件执行。npm i fork-ts-checker-webpack-plugin --save-dev
//?webpack.base.js
//?rules
{
????test:?/\.(t|j)s$/,
????exclude:?/node_modules/,
????use:?[
??????{
????????loader:?'ts-loader',
????????options:?{
??????????//?指定特定的ts编译配置,为了区分脚本的ts配置
??????????configFile:?path.resolve(__dirname,?'../tsconfig.loader.json'),
??????????//?对应文件添加个.ts或.tsx后缀
??????????appendTsSuffixTo:?[/\.vue$/],
??????????transpileOnly:?true,?//???关闭类型检查,即只进行转译
????????},
??????},
????],
}
//?plugins?push
new?ForkTsCheckerWebpackPlugin()
至此项目基本可以跑起来了,那么有个问题了:Ts 可以编译为指定版本的 js,那么还需要 babel 么?
tsc 的 target 只转译语法,不集成 polyfill,所以还是得要 babel。
比如把箭头函数转成普通 function、aysnc + await 变成 Promise.then,这是语法转译;
但你运行环境里如果没有 Promise.prototype.finally,那没有就还是没有。
因此我们项目里还是需要 babel.
Webpack 转译 Typescript 现有方案:
综合考虑性能和扩展性,目前比较推荐的是?babel+fork-ts-checker-webpack-plugin
?方案。
在 babel7 之前,是需要同时使用 ts-loader 和 babel-loader 的,其编译过程?TS > TS 编译器 > JS > Babel > JS?
。可见编译了两次js,效率有些低下。但是 babel7 出来之后有了解析 typescript 的能力,有了这一层面的支持,我们就可以只使用 babel,而不用再加一轮 ts 的编译流程了。
在 babel 7 中,我们使用新的?@babel/preset-typescript
?预设,结合一些插件便可以解析大部分的 ts 语法。
那么,Babel 是如何处理 TypeScript 代码的呢?
Babel 删除了所有 TypeScript,将其转换为常规的 JavaScript,并继续以它自己的方式处理。删除了 typescript 则不需要进行类型检查,不会有烦人的类型错误提醒,因此编译速度提升,开开心心编程????
当然,类型安全性检查必不可少,我们可以统一在某个时间集中处理,增加 script:
"check-types":?"tsc?--watch",
添加 babel 解析 typescript
#?安装以下依赖?--save-dev
#?webpack?loader
babel-loader
#?babel?核心
@babel/core
#?智能转换成目标运行环境代码
@babel/preset-env
#?解析?typescript?的?babel?预设
@babel/preset-typescript
#?polyfill?
@babel/plugin-transform-runtime
#?支持?ts?类的写法
@babel/plugin-proposal-class-properties?
#?支持三点展开符
@babel/plugin-proposal-object-rest-spread
#?安装以下依赖?--save
@babel/runtime
@babel/runtime-corejs3
"core-js":?"^3.11.0",
删除 ts-loader, 添加 babel-loader
{
????test:?/\.(t|j)s$/,
????exclude:?/node_modules/,
????use:?[
??????{
????????loader:?'babel-loader',
??????},
????],
}
项目根目录添加 babel 配置文件 babel.config.js
module.exports?=?{
??presets:?[
????[
??????'@babel/preset-env',
??????{
????????useBuiltIns:?'usage',?//?按需引入?polyfill
????????corejs:?3,
??????},
????],
????[
??????'@babel/preset-typescript',?//?引用Typescript插件
??????{
????????allExtensions:?true,?//?支持所有文件扩展名,否则在vue文件中使用ts会报错
??????},
????],
??],
??plugins:?[
????[
??????'@babel/plugin-transform-runtime',
??????{
????????corejs:?3,
??????},
????],
????'@babel/proposal-class-properties',
????'@babel/proposal-object-rest-spread',
??],
}
项目中代码规范集成了 EditorConfig, Prettier, ESLint, Husky, Lint-staged,以及如何解决 Prettier 和 ESLint 的冲突的问题,具体实现可以参考?《从 0 开始手把手带你搭建一套规范的 Vue3.x 项目工程环境》这篇文章,讲的很详细这里不再赘述。
利用 inquirer 选择配置好的提交类型,以及配合 commitlint 实现 commit 检查
npm?i?inquirer?shelljs?@commitlint/{cli,config-conventional}?-D
添加 package.json 的 script :
"commitlint":?"commitlint?-e",?
"commit":?"node?commit/git-commit.js"
创建 commit/git-commit.js 文件
const?shell?=?require('shelljs')
const?inquirer?=?require('inquirer')
const?prompsConfig?=?{
??ciType:?[
????{
??????type:?'list',
??????name:?'type',
??????message:?'请选择本次提交的类型:',
??????choices:?[
????????{
??????????name:?'引入新特性',
??????????value:?'feat',
????????},
????????{
??????????name:?'改进代码的结构格式/样式',
??????????value:?'style',
????????},
????????{
??????????name:?'修复?bug',
??????????value:?'fix',
????????},
????????{
??????????name:?'提升性能',
??????????value:?'perf',
????????},
????????{
??????????name:?'删除代码或文件',
??????????value:?'delete',
????????},
????????{
??????????name:?'其他修改,?比如改变构建流程、或者增加依赖库、工具等',
??????????value:?'chore',
????????},
????????{
??????????name:?'重构',
??????????value:?'refactor',
????????},
????????{
??????????name:?'撰写文档',
??????????value:?'docs',
????????},
????????{
??????????name:?'增加测试',
??????????value:?'test',
????????},
????????{
??????????name:?'更新打包文件',
??????????value:?'build',
????????},
????????{
??????????name:?'初次提交',
??????????value:?'init',
????????},
????????{
??????????name:?'发布/版本标签',
??????????value:?'release',
????????},
????????{
??????????name:?'部署功能',
??????????value:?'deploy',
????????},
????????{
??????????name:?'代码回滚',
??????????value:?'revert',
????????},
????????{
??????????name:?'CI持续集成修改',
??????????value:?'ci',
????????},
??????],
????},
??],
??ciMsg:?{
????type:?'input',
????name:?'msg',
????message:?'请输入提交文本:',
????validate:?function?(value)?{
??????if?(value)?{
????????return?true
??????}
??????return?'文本必须输入!'
????},
??},
}
async?function?gitCommit()?{
??let?{?type?}?=?await?inquirer.prompt(prompsConfig.ciType)
??let?{?msg?}?=?await?inquirer.prompt(prompsConfig.ciMsg)
??shell.exec(`git?commit?-m?"${type}:?${msg}"`,?function?()?{
????console.log(`\n提交脚本:?git?commit?-m?"${type}:?${msg}"`)
??})
}
gitCommit()
配置 commitlint 类型,创建 commitlint.config.js 文件:
module.exports?=?{
??extends:?['@commitlint/config-conventional'],
??rules:?{
????'type-enum':?[2,?'always',?[
??????'build',?'chore',?'ci',?'feat',?'docs',?'fix',?'perf',?'revert',?'refactor',?'style',?'test',?'init',?'build',?'release',?'delete'
?????]],
??}
};
完成上述操作后,git add 相关文件
,执行?npm run commit
?即可执行 commit 校验
Travis CI 是一款构建和测试的自动化工具,不仅可以提高效率,还能使开发流程更可靠和专业化,从而提高软件的价值。而且,它对于开源项目是免费的,不花一分钱,就能帮你做掉很多事情。详细介绍可以查看?阮一峰——《持续集成服务 Travis CI 教程》
首先,访问官方网站 travis-ci.org,点击右上角的个人头像,使用 Github 账户登入 Travis CI。
找到对应的仓库,打开开关添加仓库
在 github 上 setting/Developer settings/Personal access token 处生成 travis token
<img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/69ea45bccd674eaeb7023ea850aa2be1~tplv-k3u1fbpfcp-watermark.image" width="700"/>
点击对应仓库的 setting
设置环境变量 GITHUB_TOKEN 为刚才 github 处生成的 token
<img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a1594556dfc3449698070dfb99c18f59~tplv-k3u1fbpfcp-watermark.image" width="700"/>
创建 .travis.yml 配置文件:
language:?node_js
node_js:
??-?12
branchs:
??only:
????-?master
cache:
??directories:
????-?node_modules
install:
??-?yarn?install
scripts:
??-?yarn?build
deploy:
??provider:?pages
??local_dir:?dist
??skip_cleanup:?true
??#?在 GitHub 上生成的令牌,允许 Travis 推送代码到你的仓库。
??#?在仓库对应的 Travis 设置页面中配置,用于安全控制。
??github_token:?$GITHUB_TOKEN
??keep_history:?true
??on:
????branch:?master
这样,当你 push 到 master 或者 pr 合并到 master 的时候,就会触发部署脚本的执行,将生成的 dist 推送至 gh-pages 分支
<img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1710d33f1a1c4da18ad28ef2c4805f34~tplv-k3u1fbpfcp-watermark.image" width="700"/>
构建时间比 webpack4 长,可能是由于 ts 的引入,以及 happypack 多进程构建的移除造成时间略长
dev server 不会自增 port
fork-ts-checker-webpack-plugin 无法检测 vue 中的 ts 类型错误
捣鼓了挺长一段时间,也了解了蛮多工程化的东西,虽然不一定能用于实际项目中,但还是算有所收获吧!
END
推荐阅读??点击标题可跳转
5个常问的 Vue3 优势点
不要再用 Vue2 的思维写 Vue3 了
比较JS合并数组的各种方法及其优劣
觉得本文对你有帮助?请分享给更多人
关注下方「前端开发博客」,提升前端技能
如果觉得这篇文章还不错,来个【分享、点赞、在看】三连吧,让更多的人也看到~
???“分享、点赞、在看” 支持一波??
cs