美文网首页vue
vite+vue+ssg做官网 再记录一下项目创建

vite+vue+ssg做官网 再记录一下项目创建

作者: 云鹤道人张业斌 | 来源:发表于2022-12-06 14:03 被阅读0次

    为什么选择插件vite-ssg + vite-plugin-pages创建官网?

    1. CSR、 SSR、 SSG 和 ISR

    适合高度动态的 Web 应用程序
    客户端渲染 CSR. : 典型代表:单页面应用,内容都是js动态渲染
    服务器端渲染 SSR : 在服务端获取数据组装页面,返回到浏览器是html,对服务器要求高,主要应用是交互多的页面需要seo的

    适合高度静态的web程序
    静态站点生成 SSG: 在build的的时候就已经生成好静态页面,放在服务端的也是静态页面,博客,静态官网都非常合适
    增量静态再生 ISR:ISR 是 SSG 的下一个改进,它定期构建和重新验证新页面,以便内容永远不会过时

    显而易见,做个官网ssg就非常合适,正好相关插件vite-ssg也有,配合多页面插件vite-plugin-pages来尝试一下

    2. 创建项目步骤

    第一步:三种任选其一执行
    
    npm create vite@latest
    yarn create vite
    pnpm create vite
    

    按照命令提示写项目名称,我选择vue-ts作为项目就可以生成项目了

    第二步:进入项目,正常启动后准备安装
    vite-ssg 需要vue-router 和 @vueuse/head
    yarn add vite-plugin-pages vite-ssg vue-router @vueuse/head vite-plugin-md -D
    

    vite-plugin-md 该插件支持使用makdown语法转换为vue
    支持在vue文件中直接引入md文件组件,也可以在md文件中直接使用vue组件
    需要配置

     ViteVue({
                include: [/\.vue$/, /\.md$/],
            })
    
    第三步:修改配置内容

    修改main.ts

    import './style.css'
    import App from './App.vue'
    import { ViteSSG } from 'vite-ssg'
    import routes from '~pages'
    
    export const createApp = ViteSSG(
        App,
        { routes }
    );
    

    如果~pages有提示找不到模块或相应的类型声明,其实文档中已有说明
    在vite-env.d.ts中加入声明

    // vite-env.d.ts
    /// <reference types="vite-plugin-pages/client" />
    

    同理在tsconfig.json中加入也是一样的,两个地方选择一个加入就可以

    "compilerOptions": {
        "types": [
          "vite-plugin-pages/client"
        ],
      },
    

    修改build脚本

    -   "build": "vite build"
    +   "build": "vite-ssg build"
    

    修改vite.config.ts

    import { defineConfig } from "vite";
    import ViteVue from "@vitejs/plugin-vue";
    import VitePages from 'vite-plugin-pages';
    import ViteMarkdown from 'vite-plugin-md';
    import AutoImport from 'unplugin-auto-import/vite'
    import Components from 'unplugin-vue-components/vite'
    
    export default defineConfig({
        plugins: [
            ViteVue({
                include: [/\.vue$/, /\.md$/],
            }),
    
            VitePages({
                extensions: ['vue', 'md'],
                exclude: ['**/components/*.vue']
            }),
    
            ViteMarkdown(),
            AutoImport({
              imports: ['vue']
            }),
            Components({
                extensions: ['vue', 'md']
            }),
        ],
    });
    

    修改app.vue

    <template>
      <router-view />
    </template>
    
    第四步:根据插件vite-plugin-pages的配置项来新建文件夹

    主要看以下几个配置项

    interface Options {
        /**
         * Paths to the directory to search for page components.
         * @default 'src/pages'
         */
        dirs: string | (string | PageOptions)[];
        /**
         * Valid file extensions for page components.
         * @default ['vue', 'js']
         */
        extensions: string[];
     /**
         * List of path globs to exclude when resolving pages.
         */
        exclude: string[];
     /**
         * Extend route records
         */
        extendRoute?: (route: any, parent: any | undefined) => any | void;
    }
    

    dirs 默认是src/pages, 这就是我们新建页面的地方。

    extensions默认是['vue', 'js']src/pages中默认可以转换成页面的文件类型,这里我们将vue文件和md文件转换就可以了,配置为extensions: ['vue', 'md']

    extendRoute通过这个配置可以为路由信息增加额外信息,自由发挥

    exclude 可以排除某些vue文件不生成页面。比如我的页面中有组件: exclude: ['**/components/*.vue']

    tip:文档中提到一个匹配所有404路由的方式:新建一个[...all].vue文件即可。
    src/pages/[...all].vue -> /* (/non-existent-page)

    第五步: 最后我们看一下目录结构和生成的dist文件夹
    企业微信截图_81083726-a904-42a8-9da6-b39c5eb4705f.png

    可以发现

    • 1.项目会默认打开src/pages/index.vue
    • 2.test文件夹中的components中的child不会生成页面,配置忽略了
      1. md文件也可以生成页面

    3. 继续完善项目的其他配置

    可以选择性观察本篇vite + vue3 多页面实战优化续集:eslint+lint-staged+husky+stylelint

    官网有新的一行命令生成eslint: npm init @eslint/config可以替代 npx eslint --init,
    同样的一步步往下选择

    上述文章中安装eslint非常顺利,这次配置eslint出现了不少错误提示.可以发现与上次安装插件相比的eslint-config-standard 变成了eslint-config-standard-with-typescript

        "@typescript-eslint/eslint-plugin": "^5.44.0",
        "eslint": "^8.28.0",
        "eslint-config-standard-with-typescript": "^23.0.0",
        "eslint-plugin-import": "^2.26.0",
        "eslint-plugin-n": "^15.5.1",
        "eslint-plugin-promise": "^6.1.1",
        "eslint-plugin-vue": "^9.8.0",
    

    有变化就要踩坑,从插件名称上看是主要针对ts的写法校验,这里记录一下这次出现的问题:

    • 问题一:Error: Error while loading rule '@typescript-eslint/dot-notation': You have used a rule which requires parserServices to be generated. You must therefore provide a value for the "parserOptions.project" property for @typescript-eslint/parser.

    starkoverflow有提到要在.eslintrc 中加入project

    parserOptions: {
       project: ['./tsconfig.json'],
       extraFileExtensions: ['.vue']
     }
    
    • 问题二:The extension for the file (.vue) is non-standard. You should add parserOptions.extraFileExtensions to your config。 如上述配置加入extraFileExtensions: ['.vue']
    • 问题三:This rule requires the strictNullChecks compiler option to be turned on to function correctly @typescript-eslint/strict-boolean-expressions

    可以在.eslintrc 的rules中设置为警告,并在tsconfig.json中开启"strictNullChecks": true,修改tsconfig.json记得重启项目生效 starkoverflow

    // .eslintrc
    rules: {
    "@typescript-eslint/strict-boolean-expressions": "warn",
    }
    
    // tsconfig.json
      "compilerOptions": {
        "strictNullChecks": true
    }
    

    以前的null严格检查为了向下兼容都是默认关闭的,现在新建项目建议都开启null检查,可以避免很多空值导致的bug
    如果你不想用它,也可以直接设为关闭:‘off’

    关于问题二三我在eslint官网也看到了相关配置

    {
        "root": true,
        "extends": [
            "eslint:recommended",
            "plugin:@typescript-eslint/recommended"
        ],
        "parser": "@typescript-eslint/parser",
        "parserOptions": { "project": ["./tsconfig.json"] },
        "plugins": [
            "@typescript-eslint"
        ],
        "rules": {
            "@typescript-eslint/strict-boolean-expressions": [
                2,
                {
                    "allowString" : false,
                    "allowNumber" : false
                }
            ]
        },
        "ignorePatterns": ["src/**/*.test.ts", "src/frontend/generated/*"]
    }
    
    • 问题四:Do not use a triple slash reference for vite/client, use import style instead @typescript-eslint/triple-slash-reference

    不鼓励使用三斜线,在vite-env.d.ts中有vite/client类型引入。关掉这个规则吧

    // .eslintrc
    rules: {
    '@typescript-eslint/triple-slash-reference': 'off'
    }
    
    • 问题五:在.eslintrc.cjs中的module.exports飘红:However, that TSConfig does not include this file. Either:
    • Change ESLint's list of included files to not include this file
    • Change that TSConfig to include this file
    • Create a new TSConfig that includes this file and include it in your parserOptions.project
      提示使用了parserOptions.project.但是tsconfig.json不包含本文件

    那就在tsconfig.json的include数组中加入.eslintrc.cjs.重启生效

    "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue",".eslintrc.cjs"],
    
    • 问题六: image.png

    加入parser解决,这里的@typescript-eslint/parser就不需要单独安装了。
    eslint-config-standard-with-typescript文档中说了
    This package has @typescript-eslint/parser in dependencies.

    parserOptions: {
        parser: '@typescript-eslint/parser',
      }
    
    • 问题七: .vue文件可以格式化,但是.ts,.less文件不能正常格式化的

    原因:我的vscode在设置中的用户开启了format on save,这是针对我的编辑器。
    此时我还没在项目中新建针对工作区.vscode/settings.json文件。所以此时保存自动格式化的能力完全来源于用户中的format on save

    解决:

    1. 为了多人开发保持项目的统一,我应该关闭我自己的用户中的format on save,关闭后任何文件保存就不会自动格式化了
    2. 新建.vscode/settings.json文件,加入以下配置就会修改每个人的工作区配置,达到项目配置的统一了
    "editor.codeActionsOnSave": {
        "source.fixAll.eslint": true,
        "source.fixAll.tslint": true,
        "source.fixAll.stylelint": true
      }
    
    • 问题八: . 当保存文件时,你会发现单引号或者最后面的分号,保存的时候会消失又出现,并不能正确按照eslint的规则格式化.

    直接修改工作区配置,在.vscode/settings.json中加入

    关闭编辑器的格式化,按照eslint的规则来
    {
      "editor.formatOnSave": false,
    }
    

    当然你也可以选择性加入使用prettier,我这里稍微写一下(以下prettier内容可以跳过)

    这里使用prettier 集成到 eslint 的校验中
    第一步新建json文件

    echo {}> .prettierrc.json
    
    // .prettierrc.json
    {
        "semi": false,
        "singleQuote": true,
        "trailingComma": "none"
      }
    
    • eslint-config-prettier关闭可能与 prettier 冲突的规则
    • eslint-plugin-prettier 使用 prettier 代替 eslint 格式化

    第二步安装

    
    npm i prettier  eslint-config-prettier eslint-plugin-prettier -D
    

    第三步:在 .eslintrc.cjs 三个地方 加入prettier.

    module.exports = {
      extends: [
        'plugin:vue/vue3-essential',
        'standard-with-typescript',
        'prettier'
      ],
      plugins: [
        'vue',
        '@typescript-eslint',
        'prettier'
      ],
      rules: {
        'prettier/prettier': 'error',
      }
    }
    
    
    • 问题八: 项目使用了unplugin-auto-import自动导入,但是eslint会检测Cannot find name ‘ref’

    解决:

    • 先在vite.config.tsunplugin-auto-import/vite配置项中加入eslintrc.enabled 开启为true
    • npm run dev 运行项目,此时项目根目录会自动生成.eslintrc-auto-import.json文件
    • eslintrc.cjs 的extends加入该文件
    • 重启项目生效。生效后记得删掉eslintrc.enabled,避免重复生成
    // eslintrc.cjs
    extends: [
        'plugin:vue/vue3-essential',
        'standard-with-typescript',
        'prettier',
        './.eslintrc-auto-import.json'
      ]
    
    // vite.config.ts
    import AutoImport from 'unplugin-auto-import/vite'
    
    export default defineConfig({
         AutoImport({
          imports: ['vue', 'vue-router'],
          eslintrc: {
            enabled: true
         }
        }),
    })
    
    • 问题九: .stylelintrc.js require() of ES modules is not supported. require() of /Users/ruios/web/wisbayar-website/.stylelintrc.js from /Users/ruios/web/wisbayar-website/node_modules/cosmiconfig/dist/loaders.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules. Instead rename .stylelintrc.js to end in .cjs, change the requiring code to use import(), or remove "type": "module"

    vscode提示报错,less文件也没有正常校验。其实上面说的很明确了,本次新建的项目package.json中默认有"type": "module",这种情况下,我们平常新建的.stylelintrc.js或者.eslintrc.js 里面都是使用的module.exports,和定义"type": "module"完全使用es模块的import方式是不兼容的。

    解决:将.stylelintrc.js改为.stylelintrc.cjs,用后缀名使其识别为commonjs方式导出,修改后less文件不规范的地方也被正常识别红色波浪了

    2023年1月12新增: 在项目使用过程中发现新的配置问题

    • 问题十:在vite-ssg的github项目issue中问的最多的就是打包的时候报错:"window is not defined","document is not defined" .

    打包是在服务器,是没有BOM浏览器相关的东西的。所以在使用window的时候,我们分两种情况来使用

    1. 初始化的时候,可以在ViteSSG第三个参数函数中的isClient来判断是否是浏览器中。npm vite-ssg还有详细的案例告诉我们vuex和initialState来保持数据持久的方式
    export const createApp = ViteSSG(App, { routes }, ({ app, router, routes, isClient, initialState }) => {
    //   app.provide('$wow', WOW)
      if (isClient) {
        window.onload = fontSize()
      }
    })
    
    1. 当写在hook中需要使用window的时候,可以放在onBeforeMount,onMounted生命周期中
    export default function () {
      const isMobile = ref(false)
    
      const resizeHandler = () => {
        if (!document.hidden) {
          const rect = document.body.getBoundingClientRect()
          isMobile.value = rect.width - 1 < 750
        }
      }
      onMounted(() => {
        resizeHandler()
        window.addEventListener('resize', resizeHandler)
      })
      onBeforeUnmount(() => {
        window.removeEventListener('resize', resizeHandler)
      })
      return { isMobile }
    }
    
    
    
    1. 还提到了一个第三方插件报window错误的话,异步引入
    export const install = ({ isClient, app }) => {
      if (isClient)
        import('vue3-scroll-spy').then(({ registerScrollSpy }) => {
          registerScrollSpy(app)
        })
    }
    // 你要说想在单个页面引入,那就在onMounted中
      onMounted(() => {
          import('vue3-scroll-spy').then(({ registerScrollSpy }) => {
          registerScrollSpy(app)
        })
      })
    
    • 问题十一:当我想在这个项目中使用animate.css 加wowjs实现滚动动画的时候。出现了些意外

    先安装

    npm i animate.css wowjs
    

    main.ts引入

    import 'animate.css/animate.min.css'. // 这是
    import { WOW } from 'wowjs'
    
     new WOW({
      boxClass: 'wow',    //需要执行动画元素的Class
      animateClass: 'animated',    //animation.css动画的Class
      offset: 0,    //距离可视区域多少开始执行动画
      mobile: true,    //是否在移动设备执行动画
      live: true    //异步加载的内容是否有效
      }).init()
    
    上面都是默认配置,直接使用默认配置
     new WOW().init()
    

    !!注意
    这里单独安装了animate.css,它的类名我们可以从官网复制。它和wow里面自己依赖的样式名不一样,缺少了前缀animate__

    使用

    <div class="wow animate__animated animate__bounce"></div>
    

    滚动动画没生效,浏览器下面有错误WOW.js cannot detect dom mutations, please call .sync() after loading new content.
    MutationObserver is not supported by your browser.
    百度得知需要支持异步的内容,改成这样。提示是没有了,但是滚动动画还是无效。

    new WOW({live: false}).init()
    

    接下来,尝试在isClient中执行,或者import后执行,均无效无报错。
    我在单个页面中单独引入wowjs,并在onMounted中初始化。来了个新的报错:Cannot set properties of undefined (setting 'getPropertyValue')

    原因:查看源码得知,只是个很老的库了,直接导出的wow单例,里面用到的外部this,在vue3中肯定是没有的,自然在挂在一些方法的时候就报错了。

    解决

    1. 到github找个wow压缩包放入public文件中,在index.html中引入吧。生效
     <script type="text/javascript" src="/wow.min.js"></script>
        <script type="text/javascript">
          new WOW().init()
        </script>
    
    1. 发现还有个wow.js,安装它。看源码了解到它写了UMD导出,可以使用。
    npm i wow.js animate.css
    

    使用。样式还是跟上面一样,使用animate.css中的样式

    // main.ts
    import 'animate.css/animate.min.css'
    import WOW from 'wow.js'
    
    new WOW().init()
    
    1. 其实wow.js这个库作者已经废弃,推荐使用aos。这个就更好了,再次向下滚动后到视野会再次触发动画

    下面单独说一下aos 版本,npm介绍上还是第一版本
    aos 有两个版本,第一版aos 有自己的少量动画,配置较少,且不能结合animate.css
    使用第二版 aos@next,详细介绍到github仓库去看

    安装
    npm i aos@next animate.css
    

    使用要用到它的配置项。这里我们还是使用animate.css,效果更多。就不需要引入aos的样式了

    // main.ts
    import 'animate.css/animate.min.css'
    import AOS from 'aos'
    
    AOS.init({
    // 这个默认是关闭的,它会把`data-aos`上要写的动画样式名,自动加到class上,这样才会有第三方动画效果
      useClassNames: true,  
    // 这个就是关闭掉初始化的样式名,默认值,也就是默认样式名是'aos-init'。这里选用第三方样式,就不要被它内置的干扰了,去掉它
      initClassName: null,
    // 这里的默认值是'aos-animate',我们替换为animate.css的样式名
      animatedClassName: 'animate__animated'
    })
    

    在公共样式表做样式覆盖

    
    [data-aos] {
      visibility: hidden;
    }
    [data-aos].animate__animated {
      visibility: visible;
    }
    

    最后使用起来

    <div data-aos="animate__fadeInLeft"></div>
    

    最后配置好的项目,我放到这里gitee,直接取用
    最新vite + ssg 项目配置地址

    相关文章

      网友评论

        本文标题:vite+vue+ssg做官网 再记录一下项目创建

        本文链接:https://www.haomeiwen.com/subject/voqaxdtx.html