1. 前言
笔者两年前曾写过一篇文章《Webpack4 搭建 Vue 我的项目》,起初随着 webpack5 和 vue3 的面世,始终想降级下我这个 createVue 我的项目,然而苦于没有工夫(其实是因为懒),始终迁延至今。捣鼓了好几天,终于搭建好整个我的项目,因而仅以此文记录降级搭建的过程。
PS: 其实也能够用官网脚手架搭建的,为何要本人从头做起呢?
有脚手架我不必,我就折腾。哎,就是玩儿~😄
2. 筹备工作
为何降级?除了折腾外,便是享受新版本带给咱们的新个性体验。
Webpack5 的新个性
- 长久化缓存
- moduleIds & chunkIds 的优化
- 更智能的 tree shaking
- Module Federation
- …
Vue3 的新个性
- 更小
- 更快
- 增强 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
3. 我的项目搭建
此文并不是从零搭建,而是在 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 现有计划:
计划 | 1 | 2 | 3 |
---|---|---|---|
单过程计划 (类型检查和转译在同一个过程) | ts-loader(transpileOnly 为 false) | awesome-typescript-loader | |
多过程计划 | ts-loader(transpileOnly 为 true) + fork-ts-checker-webpack-plugin | awesome-typescript-loader + 自带的 CheckerPlugin | babel + fork-ts-checker-webpack-plugin |
综合思考性能和扩展性,目前比拟举荐的是 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',
],
}
4. 代码标准
我的项目中代码标准集成了 EditorConfig,Prettier,ESLint,Husky,Lint-staged,以及如何解决 Prettier 和 ESLint 的抵触的问题,具体实现能够参考《从 0 开始手把手带你搭建一套标准的 Vue3.x 我的项目工程环境》这篇文章,讲的很具体这里不再赘述。
5. 提交标准
利用 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 校验
6. 构建部署 Travis CI
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″/>
7. 存在问题及总结
- 构建工夫比 webpack4 长,可能是因为 ts 的引入,以及 happypack 多过程构建的移除造成工夫略长
- dev server 不会自增 port
- fork-ts-checker-webpack-plugin 无奈检测 vue 中的 ts 类型谬误
捣鼓了挺长一段时间,也理解了蛮多工程化的货色,尽管不肯定能用于理论我的项目中,但还是算有所播种吧!
8. 更多举荐
Canvas 进阶(一)二维码的生成与扫码辨认
Canvas 进阶(二)写一个生成带 logo 的二维码 npm 插件
Canvas 进阶(三)ts + canvas 重写”辨色“小游戏
Canvas 进阶(四)实现一个“刮刮乐”游戏
Canvas 进阶(五)实现图片滤镜成果
Canvas 进阶(六)实现图片压缩性能
VUI 创立日志 (一)——图片懒加载指令的实现
VUI 创立日志 (二)——防抖节流组件的实现
前端算法题目解析(一)
前端算法题目解析(二)
繁难路由实现——(hash 路由)
繁难路由实现——(history 路由)