# Vite
{%hackmd BJrTq20hE %}
## 安裝vite:
-
`npm init vite@latest`
Or 直接指定项目名称和你想要使用的模板
`npm init vite@latest my-vue-app -- --template vue`
Vite快速開發入門: https://www.gushiciku.cn/pl/gXvk/zh-hk
## 安裝配置Vue-Router:
1. `npm install vue-router@next --save`
2. 在src目錄下創建一個文件夾router/index.js,然後添加如下一些配置:
//router首頁預設為 home.vue
```javascript=
import { createRouter, createWebHashHistory } from 'vue-router';
const router = createRouter({
history: createWebHashHistory(),
routes: [
{ path: '/', component: () => import('../views/home.vue') }
]
});
export default router
```
3. 在main.js文件中引入Vue-Router:
```javascript=
import router from './router';
createApp(App).use(router).mount("#app");
```
上面createApp(App)改成
```javascript=
const app = createApp(App)
app.use(router)
app.mount('#app')
```
## 安裝scss編譯器:
- `npm install -D sass`
## 檔案路徑別名設置(不像cli有 '@' or '~' 等符號):
- [別名設置](https://ithelp.ithome.com.tw/articles/10270465?sc=hot),[環境變數設定](https://hackmd.io/@Jui-Cheng/Hk9fJ5bKi),[`process.cwd()` vs `__dirname` 有何不同](https://stackoverflow.com/questions/9874382/whats-the-difference-between-process-cwd-vs-dirname)
> `process.cwd()`:傳回我們運行 node 時的目錄
`__dirname`:傳回目前運行檔案所在的目錄。
```javascript=
//vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// 法一:
const { resolve } = require('path');
// 法二:
import { resolve } from 'node:path';
const rootPath = resolve(process.cwd()) // 返回目前工作目錄
const srcPath = resolve(__dirname, 'src') // 返回src目錄。
export default defineConfig({
base: './',
plugins: [vue()],
resolve: {
alias: {
'~': rootPath,
'@': srcPath,
'/images': 'src/assets/images',
},
},
})
```
使用:
  `import Header from "/@/components/Header.vue";`
  `<img src='/images/xxx.png'/>`
## 動態圖片路徑問題:
- 法一:https://vitejs.dev/guide/assets.html#importing-asset-as-url
```javascript=
import imgUrl from './img.png'
```
- 法二:使用相對路徑
```jsx=
// 以下寫法皆可
image.src = '../assets/textures/door.jpg'
image.src = '/assets/textures/door.jpg'
```
- 法三:https://vitejs.dev/guide/assets.html#new-url-url-import-meta-url
e.g.:
```javascript=
const url = new URL(url [, base])
const url = new URL('/foo', 'https://example.org/');
// https://example.org/foo
```
- url是一个表示绝对或相对 URL 的 DOMString。如果url 是相对 URL,则会将 base 用作基准 URL。如果 url 是绝对 URL,则无论参数base是否存在,都将被忽略。
- base 可选
是一个表示基准 URL 的 DOMString,在 url 是相对 URL 时,它才会起效。如果未指定,则默认为 ''。
>
sample:
```javascript=
const getImgSrc = (url) => new URL(`./assets/${url}`, import.meta.url).href;
image.src = getImgSrc('door.jpg');
```
- `import.meta.url`:返回当前模块的 URL 路径。
举例来说,当前模块主文件的路径是`https://foo.com/main.js`,`import.meta.url`就返回这个路径。如果模块里面还有一个数据文件`data.txt`,那么就可以用下面的代码,获取这个数据文件的路径。
`new URL('data.txt', import.meta.url)`
## github發布部屬
https://jerry-yeh.github.io/vue-3/20210911/13819/
- 環境設定檔(方式一)
透過 `process.env.NODE_ENV` 來判斷 Server 執行在開發或正式環境中
```javascript=
// vite.config.js
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import path from 'path';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
build: {
minify: true,
},
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
base: process.env.NODE_ENV === 'production' ? '/<REPO>/' : './',
});
```
`<REPO>`為github路徑
- 直接在npm指令設定(方式二)
```javascript=
// package.json
{
"scripts": {
"dev": "vite",
"build": "vite build --base=/<REPO>/",
"serve": "vite preview"
},
}
```
### gh-pages 套件 ---
1. `npm install --save gh-pages`
1. 設定 Github Page 的網址:
```json=
// package.json
{
"name": "realtime-weather-app",
"homepage": "https://myusername.github.io/my-app",
// ...
}
```
1. 在script添加兩行指令:
```json=
// package.json
{
"scripts": {
"predeploy": "npm run build",
"deploy": "gh-pages -d dist", // react為build
// ...
}
}
```
1. `npm run deploy`
### vite reactRouter 打包問題:[解法](https://blog.csdn.net/qq_24993119/article/details/124988629)
- baseUrl設定只能影響非reactRouter路徑,因此router需另外設定
```jsx=
return (
<BrowserRouter basename={import.meta.env.BASE_URL}>
<App />
</BrowserRouter>
);
```
其他環境變量:[env-variables](https://cn.vitejs.dev/guide/env-and-mode.html#env-variables)
- **`import.meta.env.MODE`**: {string} 应用运行的[模式](https://cn.vitejs.dev/guide/env-and-mode.html#modes)。
- **`import.meta.env.BASE_URL`**: {string} 部署应用时的基本 URL。他由[`base` 配置项](https://cn.vitejs.dev/config/shared-options.html#base)决定。
- **`import.meta.env.PROD`**: {boolean} 应用是否运行在生产环境。
- **`import.meta.env.DEV`**: {boolean} 应用是否运行在开发环境 (永远与 `import.meta.env.PROD`相反)。
- **`import.meta.env.SSR`**: {boolean} 应用是否运行在 [server](https://cn.vitejs.dev/guide/ssr.html#conditional-logic) 上。
## 安裝element ui套件:
  `npm install element-plus --save`
- 引入:
```javascript=
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
app.use(ElementPlus)
```
el-upload —手動上傳檔案,限制上傳檔案數量,檔案型別校驗等(手動設定)
https://www.796t.com/article.php?id=250992
upload非空判斷: https://blog.csdn.net/weixin_43753330/article/details/95990910
## vue3 報錯解決:找不到模組‘xxx.vue’或其相應的型別宣告。
https://iter01.com/528992.html
- 報錯原因:typescript 只能理解 .ts 檔案,無法理解 .vue檔案
在預設`env.d.ts`加入設定
```jsx=
declare module '*.vue' {
import { ComponentOptions } from 'vue'
const componentOptions: ComponentOptions
export default componentOptions
}
```
## unplugin-auto-import
`npm i -D unplugin-auto-import`
- 找不到模組 'unplugin-vue-components/vite' 或其對應的型別宣告。
需安裝:`npm i unplugin-vue-components -D`
All:`npm i -D unplugin-auto-import unplugin-vue-components`
### 自動全域註冊組件
- 自動:[tutorial](https://blog.logrocket.com/how-to-automatically-import-register-vue-components/)
```jsx=
// .\vite.config.ts
import Components from 'unplugin-vue-components/vite'
export default defineConfig(
plugins: [
Components({ dirs: ["src/example/dir/here"] }) // 設定要自動引入的路徑
]
})
```
- 手動:[turorial-舊](https://zerotomastery.io/blog/how-to-auto-register-components-for-vue-with-vite/),[turorial-新](https://blog.csdn.net/Chuinj/article/details/129789597)
## 使用 Jsx
### [Template vs JSX - 設定教學](https://zhuanlan.zhihu.com/p/586409247)
JSX 优势:
* template 则因为语法限制原因,不能够像 JSX 那样可以支持更动态的需求。
* JSX 相比于 template 还有一个优势,是可以在一个文件内返回多个组件
在实现业务需求的时候,优先使用 template,尽可能地利用 Vue 本身的性能优化。而对于动态性要求较高的组件可以使用 JSX 来实现。(比如用 JSX 来实现动态表单生成器)
>
1. 安裝 `npm i -D @vitejs/plugin-vue-jsx`
2. 配置:
```jsx=
// .\vite.config.js
import vueJsx from "@vitejs/plugin-vue-jsx"; // 配置vue使用jsx
export default defineConfig({
plugins: [vue(), vueJsx()],
});
```
1. 使用:
注意:==script 中 lang 要改成 jsx==。也可以與`setup`同時使用
```jsx=
// render.vue
<script lang="jsx">
import { ref } from "vue";
export default {
setup() {
const count = ref(100);
return () => <div>count is: {count.value}</div>;
},
};
</script>
```
### 使用 jsx 教學:
[《Vue3中使用JSX简明语法》](https://segmentfault.com/a/1190000042042220)、[使用 h 渲染 slot 範例](https://blog.csdn.net/leekuikui/article/details/126876400)、[jsx更詳細用法](https://segmentfault.com/a/1190000040712149)
- sample code:
1. `props`:屬性裡的雙大括號
2. `slot`:元件中間的雙大括號,前面的 key 是 slot name
```jsx=
render(row) {
return (
<BaseTooltips label="刪除">
<n-popconfirm class="max-w-fit" positiveButtonProps={{ type: 'error' }} onPositiveClick={() => deleteItem()}>
{{
trigger: () => (
<n-button circle tertiary type="error" size="large">
<n-icon size="25"><Trash /></n-icon>
</n-button>
),
default: () => (
'請確認是否刪除'
)
}}
</n-popconfirm>
</BaseTooltips>
</div>
)
}
```
### 指定單 row 置放按鈕
- 只有第一行有按鈕
```jsx=
render(row) {
return (data.indexOf(row) == 0 ?
<div class="flex gap-1">
<n-button type="primary" onClick={() => console.log(data.indexOf(row))}> Play </n-button>
<n-button type="primary" onClick={() => play(row)}> bbb </n-button>
</div> : ''
)
}
```
## vue3 自行製作組件
- [vue2、3屬性繼承](https://juejin.cn/post/7157195220038189087)
主要是在需繼承父層屬性的節點上加入`v-bind="$attrs"`即可,会接收属性和事件
```jsx=
<template>
<n-tooltip placement="top" trigger="hover" v-bind="$attrs">
<template #trigger>
<slot />
</template>
<span>{{ label }}</span>
</n-tooltip>
</template>
```
- 延伸閱讀,[手把手创建Vue3组件库](https://segmentfault.com/a/1190000041592227)
## 動態載入路由、組件
- vue2 中,可以使用 webpack 自带的 require.context 批量引入模块
```jsx=
const modulesFiles = require.context('./modules', true, /\.js$/)
```
- 而在 vite 中使用`import.meta.glob`。[Glob導入-vite官網](https://cn.vitejs.dev/guide/features.html#glob-import)。
[導入組件用法](https://www.jb51.net/javascript/2917893dz.htm),[詳細說明(含webpack)](https://blog.csdn.net/guorui999/article/details/128814178)