【山竹记账前端-vue】1.搭建前端项目
大纲链接 §
[toc]
1. 使用 oh-my-env 开发环境 ⇧
快速启动开发环境 ⇧
- 下载 oh-my-env-1
- 使用
VSCode打开目录- 预装
Docker Desktop加速镜像已配置 - 预装插件
Dev Container - 已开启
wsl等 - 详见 搭建Docker开发环境
- 预装
Reopen in Container等加载完毕,可关闭当前终端窗口- 另外打开终端 默认使用
zsh - 使用
nvm install 22最新版- 单独安装
pnpm: - 首先
npm install --global corepack@latest - 然后
corepack enable - 最后
corepack prepare pnpm@11.27.0 --activate
- 单独安装
- 工作目录
~/repos在这个目录中创建项目目录 - 根目录
~即/root- 放置
.ssh目录 - 放置
.bashrc文件 - 放置
.gitconfig文件
- 放置
快速配置开发环境 ⇧
锁死
npm版本号
- 运行
npm config set save-prefix=''去除^
配置
ssh,快速使用github项目
|
|
配置
git,快速使用github项目
|
|
搭建前端框架 ⇧
- 前端技术栈
Vite 8 + Vue 3 + Typescript 7(TSX) + VueRouter 5 + Pinia - 开发环境:全程使用 我的开发环境 oh-my-env-1
node@19.9.0 (npm v8.19.2)(使用nvm use system开启)pnpm@6.32.3(推荐代替npm和yarn)- 使用淘宝
npm源加速npm config set registry=https://registry.npmmirror.com - 不推荐
npm@8.19.2(备用)、yarn@1.22.22(备用)
后续升级记录(20260920)
node@22.23.2 (npm@10.9.8)nvm alias system 22.23.2nvm alias default system
pnpm@11.27.0
创建前端项目 ⇧
- 运行
cd ~/repos - 运行
nvm use system或者升级到稳定版nvm use 22 - 创建项目,以下命令二选一:
pnpm create vite@8.3.0 mangosteen-fe-0 --template vue-tspnpm create vite@8.3.0根据脚手架提示选择选项- 项目名称:
mangosteen-fe-0 - 框架:
Vue - 框架变体-Vue官方启动器:
Official Vue Starter - 是否使用Vite 8:
Yes - 是否使用 TypeScript 语法
Yes - 选择要包含的功能
JSX支持Router(单页面应用开发)Pinia(状态管理)Vitest(单元测试)- 端到端测试
- Linter(错误预防)
- Prettier(代码格式化)
- 端到端测试框架:
Cypress - 试验特性:
- 使用
Oxfmt替代Prettier - 使用
typescript-native-bridge(tsgo)替代TypeScript
- 使用
- 包管理器:
pnpm
- 按照提示执行后续命令
- 推荐将
cd mangosteen-fe-0改为code mangosteen-fe-0使用VSCode打开
- 推荐将
|
|
安装完毕
|
|
- 虚拟软链接地址
node_modules/.pnpm - 实际安装地址
.pnpm-store/v11 - 可以节省磁盘空间
添加版本固定配置(文件) ⇧
pnpm config set save-prefix=''锁定版本;还需要在package.json中手动去除^,全局替换- 手动维护依赖版本号更新,也可以安装相关插件提示最新可用lts版本
.nvmrc运行命令echo "22.23.2" >> .nvmrc锁定版本;- 可以写脚本自动切换
node版本
- 可以写脚本自动切换
在
package.json中锁定Node.js版本 在package.json中添加配置
|
|
配置
.npmrc(适用于 npm / pnpm),在项目根目录下创建或编辑.npmrc文件,增加以下配置:
echo 'engine-strict=true' >> .npmrc1engine-strict=true让限制对
npm生效:默认情况下 engines 限制只对Yarn/Pnpm强生效或仅作警告如果使用
npm,需要在项目根目录下创建.npmrc文件才会开启严格检查
锁定包管理器
|
|
实现硬拦截,配合
preinstall脚本,防止误用其他包管理器,在package.json中添加配置
|
|
- 仅可使用
pnpm安装;运行都可
可选:修改
~/.bashrc中的命令别名,将其他包管理器都命名为pnpm
|
|
- 之后如果需要使用
npm时,只需要运行\npm --version,添加一个反斜杠即可
写到
README.md
参考
Vite 项目在 VSCode 中根目录别名配置 @ ⇧
在
webstorm中默认读取js/ts.config.json中配置的别名,VSCode需要额外配置别名
- 按
Ctrl + Shift + P搜索settings - 打开用户编辑
settings.json 添加以下字段配置
1 2 3 4{ "js/ts.preferences.importModuleSpecifier": "non-relative", "js/ts.preferences.importModuleSpecifierEnding": "minimal" }或者按
Ctrl + Shift + P董凯配置面板,搜索importModule将如图两项分别设置为
non-relative和minimalPrefers a non-relative import based on the baseUr1 or paths configured in your jsconfig.json tsconfig.json
添加路径别名
@,配置vite.config.ts
|
|
添加路径别名
@,配置tsconfig.app.json
|
|
- 部分配置继承了
node_modules/@vue/tsconfig/tsconfig.json
2. dev、build 和 preview ⇧
运行开发
pnpm dev
- 开启一个
server在Local: http://localhost:5174- 这个端口是容器
Linux的端口 VSCode做了端口自动转发- 在宿主机(
Windows)中也可访问这个端口
- 这个端口是容器
注意需要添加
--host参数,才能转发成功1 2 3 4 5 6{ "scripts": { "dev": "vite --host", "preview": "vite preview --host" } }
运行构建
- 运行
pnpm build - 遇坑(官方已修复,现无需处理)
pnpm build过程中报第三方打包错误node_modules/.pnpm/...- 处理过程就是报报错信息复制到google/ai中,尝试提示解决方法
- 在
tsconfig.json添加"skipLibCheck": true到"compilerOptions"字段中,可利用 自动补全查看 - 跳过依赖库代码检查,只需要检查项目代码即可
预览项目
pnpm preview --host- 查看
dist目录是否能正常运行 - 大约等价于
pnpm - http-serverhttp-server -p 4173 dist
3. 修改 build path 部署到 GitHub ⇧
把打包完的代码
dist部署到GitHub或服务器时必须配置build path
- 配置规则见 vite文档-开发或生产环境服务的公共基础路径
在
vite.config.js里添加base: '/'或base: '/reponame/'等'/reponame/'为github中仓库名称1 2 3 4 5 6 7 8import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' // https://vitejs.dev/config/ export default defineConfig({ base: '/mangosteen/', plugins: [vue()], })
重新打包到
pnpm build
仅是本地预览,直接
base: '/'就可以了
- 但是上传
github会有中间的项目名,base中间写仓库名称即可 - 之后部署章节中会另外说明配属的配置,可用
node获取环境变量 - 目前暂时用不到
提交完开始手动部署
git init;git add .;git commit -m 'first commit'
- git相关配置见文章 搭建docker开发环境,配置git/github,创建.ssh 密钥
- 发布到
GitHub- 创建
github仓库 - 推到远程仓库
- 创建
- 手动开启
GitHub Pages(手动部署可选)- 在仓库
settings中配置Pages - 选择
Branch为master,点击 Save - 如果直接上传
dist目录到源代码同一项目仓库(不推荐),则需要在GitHub Pages中设置路径/project-name/dist/ - 并且需要在
vite.config.ts中配置base: '/project-name/dist/',修改完重新pnpm build - 可以查看
index.html中资源路径是否已包含/project-name/dist/ - 重新上传
dist - 另外单独创建网页发布仓库,项目源代码仓库和网页仓库分开:
mangosteen-xxx-1-publish - 注意修改
vite.config.ts中配置base: '/mangosteen-xxx-1-publish/',修改完重新pnpm build base中的目录 必须与仓库名称相同- 路径写入项目描述
http://xxx.github.io/project-name/index.html
- 在仓库
使用脚本部署
项目目录下创建
bin/deploy_to_github.sh1 2 3 4 5 6 7 8 9 10#!/usr/bin/env bash rm -rf dist pnpm build cd dist git init git add . git commit -m deploy git remote add origin git@github.com:xxxx/mangosteen-xxx-1-xx.git git push -f origin master:master cd -运行
sh bin/deploy_to_github.sh添加可执行权限
chmod +x bin/deploy_to_github.sh,以后可以直接运行bin/deploy_to_github.sh
之后会直接部署到服务器,可以删掉暂时这个 base 配置
4. 项目目录结构 ⇧
Linux 中运行
tree -I "node_modules|target|.git|.vscode"1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50. ├── README.md # 项目自述文件(说明文档、运行与部署指南) ├── dist # 打包构建输出目录(执行 build 命令后生成的静态资源,用于生产环境部署) ├── env.d.ts # TypeScript 环境变量声明文件(让 TS 识别 .vue 文件和 import.meta.env 的类型) ├── eslint.config.ts # ESLint 配置文件(定义代码代码规范、统一团队代码风格) ├── index.html # 项目的入口 HTML 文件(Vite 应用的挂载主页) ├── package.json # 项目元数据及依赖管理文件(定义脚本、开发依赖、生产依赖等) ├── pnpm-lock.yaml # pnpm 依赖锁定文件(确保团队成员安装完全相同的依赖版本) ├── pnpm-workspace.yaml # pnpm 工作区配置文件(用于多包管理/Monorepo 架构,定义子项目路径) ├── public # 静态资源公共目录(存放不需要 Webpack/Vite 编译的资源,如网页图标 favicon.ico) ├── script # 自定义脚本目录 │ └── deploy_to_github.sh # 自动化部署脚本(用于一键将项目打包并推送到 GitHub Pages 等平台) ├── src # 核心源代码目录 │ ├── App.tsx # 根组件(所有页面的外壳,页面入口) │ ├── main.ts # 项目核心入口文件(初始化 Vue 实例、挂载路由、状态管理等插件) │ ├── pages # 页面组件 │ ├── const # 通用常量 │ ├── modules # 模块化业务逻辑 │ ├── components # 通用组件 │ ├── shared # 共用文件 │ ├── utils # 通用工具函数 │ ├── styles # 全局或公共样式 │ ├── assets # 静态资源:矢量图或位图 │ ├── apis # 公共接口 │ ├── hooks # 钩子文件 │ ├── types # 通用类型 │ ├── router # 路由配置目录 │ │ └── index.ts # 路由核心配置文件(定义页面路径与组件的映射关系) │ └── stores # Pinia 状态管理目录(全局数据共享) │ └── counter.ts # 计数器状态示例文件(演示如何使用 Pinia 管理全局状态) ├── tsconfig.app.json # 针对前端应用代码(src 目录)的 TypeScript 编译配置文件 ├── tsconfig.json # TypeScript 主配置文件(作为引用其它子配置的根配置) ├── tsconfig.node.json # 针对构建工具环境(如 vite.config.ts)的 TypeScript 编译配置文件 └── vite.config.ts # Vite 构建工具配置文件(配置插件、别名、代理、打包规则等) # 模块化业务逻辑 modules/ └── order/ # 以“订单模块”为例 ├── docs/ # 给人员和ai阅读的文档 ├── api.ts # [可选] 仅属于该模块的后端接口 订单相关的请求函数(如 getOrderList) ├── components/ # 仅属于该模块的私有业务组件 ├── styles/ # 仅属于该模块的私有业务样式 ├── hooks # 仅属于该模块的组合式逻辑(解耦 View 层) │ └── useXxx.ts # 封装逻辑 ├── useOrderStore | stores # [可选] 该模块独享的全局状态管理 ├── types/ # 该模块涉及的 TypeScript 类型定义 ├── utils/ # 仅属于该模块的内部工具函数 └── views/ # 该模块的路由页面入口 ├── OrderList.vue # 订单列表页 └── OrderDetail.vue # 订单详情页添加空文件夹占位文件 .keep
5. Template V.S. TSX ⇧
两者可共存
Template ⇧
|
|
TSX ⇧
默认脚手架选项已选择配置插件
@vitejs/plugin-vue-jsx
- 或者之后再安装
pnpm i -D @vitejs/plugin-vue-jsx
在
vite.config.ts中添加插件配置,添加两个选项:事件对象形式切换、自动合并属性绑定子组件根元素
|
|
- 重新运行
pnpm dev
注意 Vue 的 JSX 转换方式与 React 中 JSX 的转换方式不同,因此不能在 Vue 应用中使用 React 的 JSX 转换
- 与 React JSX 语法的一些明显区别包括:
- 可以使用 HTML attributes 比如 class 和 for 作为 props - 不需要使用 className 或 htmlFor。
- 传递子元素给组件 (比如 slots) 的 方式不同(具名插槽函数)。
- 使用 TSX 语法时,确保在
tsconfig.json中配置了"jsx": "preserve",这样的 TypeScript 就能保证 Vue JSX 语法转换过程中的完整性
JSX类型推断tsconfig.json
|
|
webstorm中注意自动识别正确的typescript语言解释器
使用
defineComponent的setup方法写TSX语法
|
|
参考
- 渲染函数案例,等价于使用如下渲染函数 / JSX 语法:
- 渲染函数 & JSX / TSX
- defineComponent()
- ComponentCustomProps:在 TSX 元素上使用没有在组件选项上定义过的 props
- github babel-plugin-jsx
函数式组件写法作为备用 ⇧
可用于无状态组件:接收
props,返回vnodes
- 在渲染过程中不会创建组件实例 (也就是说,没有 this)
- 也不会触发常规的组件生命周期钩子
禁用属性继承
FComponent.inheritAttrs = false1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78import type { SetupContext, FunctionalComponent } from 'vue' type FComponentProps = { message: string // ... } type Events = { sendMessage(message: string): void } // 具名函数式组件 export function FComponent( props: FComponentProps, ctx: SetupContext<Events> ) { // const { slots, emit, attrs } = ctx return ( <button type="button" onClick={() => { ctx.emit('sendMessage', props.message) Welcome1stPage?.emits['sendMessage']?.('msg child self') }}> {props.message} </button> ) } // 具名函数式组件的属性和事件,必须后赋值 FComponent.props = { message: { type: String, required: true } } FComponent.emits = { sendMessage: (value: unknown) => {console.log('FComponent.emits', value,)} } // 防止警告,用于DevTools等 FComponent.displayName = 'FComponent' // 匿名函数式组件 export const AnonymousFC: FunctionalComponent<FComponentProps, Events> = ( props, context ) => { return ( <button type="button" onClick={ () => { context.emit('sendMessage', props.message) Welcome1stPage?.emits['sendMessage']?.('msg child self') } }> 外部数据:{props.message} </button> ) } AnonymousFC.props = { message: { type: String, required: true } } AnonymousFC.emits = { sendMessage: (value) => {console.log('FComponent.emits', value,)} } AnonymousFC.displayName = 'AnonymousFC' // 父组件使用 function Parent() { return ( <FComponent message="msg from parent" onSendMessage={($event: string) => {console.log('parent', $event)}} /> ) }
defineComponent的函数语法 Vue@3.3+ ⇧
- 第一个参数是一个组件选项对象
setup: ComponentOptions['setup'] defineComponent函数实际上在运行时没有任何操作,仅用于提供类型推导为了能让该返回值在 TSX 中用作标签时提供类型推导支持
1 2 3const Foo = defineComponent(/* ... */) // 返回类型中可提取出一个组件的实例类型 type FooInstance = InstanceType<typeof Foo>
与组合式 API 和渲染函数或 JSX 一起使用
|
|
支持泛型
|
|
参考
6. 引入 Vue Router 5 ⇧
vue-router@5.3.1
相关文件初始代码
src/views/Foo.tsx或src/views/Bar.tsx
|
|
相关文件初始代码
src/main.ts
|
|
相关文件初始代码
src/router/index.ts
|
|
相关文件初始代码
src/App.tsx
|
|
- 手动切换路由
http://localhost:5173/foo->http://localhost:5173/bar
添加导航
src/App.tsx
|
|
7. 引入其他库 ⇧
pinia@pinia/colada@vueuse/coreaxios- 等后续引入
8. snippet 使用代码片段汇总 ⇧
VSCode 代码片段 ⇧
Ctrl + Shift + P输入snippet,回车选择
typescriptreact.son (TypeScript JSX)1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76{ "React.FC": { "prefix": "fc", "description": "React Functional Component", "body": [ "export const $TM_FILENAME_BASE: React.FC = () => {", "", " return (", " <div>$1</div>", " )", "}" ] }, "Vue Component": { "prefix": "vc", "description": "Vue Functional Component", "body": [ "import { defineComponent } from 'vue'", "", "export const $TM_FILENAME_BASE = defineComponent({", " setup: (/* props, context */) => {", " return () => (", " <div>$1</div>", " )", " }", "})" ] }, "Vue Component With Props": { "prefix": "vcp", "description": "Vue Functional Component With Props", "body": [ "import { defineComponent, type PropType } from 'vue'", "", "export const $TM_FILENAME_BASE = defineComponent({", " props: {", " propName: {", " type: String as PropType<string>", " }", " },", " setup: (/* props, context */) => {", " return () => (", " <div>$1</div>", " )", " }", "})" ] }, "Vue Component With Props and Styles": { "prefix": "vcps", "description": "Vue Functional Component With Props and Styles", "body": [ "import { defineComponent, type PropType } from 'vue'", "import s from './$TM_FILENAME_BASE.module.scss'", "", "export const $TM_FILENAME_BASE = defineComponent({", " props: {", " propName: {", " type: String as PropType<string>", " }", " },", " setup: (/* props, context */) => {", " return () => (", " <div class={s.wrapper}>$1</div>", " )", " }", "})" ] }, "Import Module SCSS": { "prefix": "ims", "body": [ "import s from './$TM_FILENAME_BASE.module.scss';" ] } }
typescript.json中状态管理文件
|
|
WebStorm 模板代码 ⇧
Vue3.x TSX文件和代码模板
|
|
- 无需
components: {},属性配置,导入的组件直接在TSX中使用即可
Webstorm实时模板
|
|
- 绑定系统变量,右侧的 Edit Variables(编辑变量) 按钮变成可选状态,点击
- 在弹出的窗口中配置 $NAME$ 变量
- 点击下拉菜单,选择或直接输入:fileNameWithoutExtension()(自动获取当前文件名,并去掉 .ts 或 .tsx 等后缀)
- 勾选 Skip if defined(如果已定义则跳过)
带
Props约束类型的Vue3.x TSX文件和代码模板
|
|
参考
- webStorm 如何像 VSCode 那样配置 snippets 代码片段
- Visual Studio Code 中的代码片段
- snippet-generator
- VSCode Snippets:提升开发幸福感的小技巧
- VS Code 代码片段完全入门指南
- VSCode代码片段变量避坑手册(9个常见错误及解决方案)
- 【VSCode代码效率革命】:掌握Snippets变量与正则的7个高阶技巧
9. 总结命令汇总 ⇧
|
|
- 之后会另存为一个
github template方便给 ai 快速启动一个新项目 - 参考模板 react-starter
- AI-如何将初始项目另存为一个 github template
- github degit
参考文章
- 前端代码 github.com/FrankFang/ptmqtd
- 我的 Vue 3 + TSX 项目
- react-mangosteen
- mangosteen-src-002
- Oh, My Docker
相关文章
- bash 脚本中如何获取当前时间日期 并格式化
- 公共基础路径
- Vue 与 React 路由守卫
- Vue JSX Compiler-powered, high-performance JSX 需要
Vue@3.6+ - npm @10coding/vite-plugin-jsx-scoped
- Visual Studio Code Snippet
- 作者: Joel
- 文章链接:
- 版权声明
- 非自由转载-非商用-非衍生-保持署名