百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

封装搭建Vue3 + Vite项目框架进阶版,值得学习收藏【前端工程化】

bigegpt 2024-08-29 11:26 4 浏览

前言

小希这次带来了进阶版的Vue3 + Vite项目框架的封装搭建

本文主要的切入点有

搭建过程

多入口打包

一般情况下,项目开发只有一个入口,只需要配置一个入口,一个项目

但有时多个同业务、同类型的项目,有很多可以复用的业务,组件,工具类等,就可以放在同一个代码库里进行维护,不用新建多个代码库

每个项目都有自己独立的入口,可以独立打包并进行部署,低耦合,不会相互影响,同时还可以复用相同的组件,业务等,可以大大地提高开发效率和后期的维护

调整项目结构目录

如上图所示,有两个项目,分别是app1,app2,每个项目都有自己独有的main.ts入口文件,App.vue文件,以及路由,仓库pinia,组件等,同时也有共有的组件,utils工具类等

配置过程

在package.json中,将下图单入口的配置

改为

{
  "scripts": {
    "dev:app1": "vite serve src/app1/ --config ./vite.config.ts",
    "dev:app2": "vite serve src/app2/ --config ./vite.config.ts",
    "build:app1": "vue-tsc && vite build",
    "build:app2": "vue-tsc && vite build"
  },


这样配置可实现项目的独立运行,独立打包

在vite.config.ts中配置:

/* 项目名称 */
//采用这种方式可以动态获取项目名称,当然,如果项目少可以手动配置
let appName = process.env.npm_lifecycle_event
appName = appName.slice(appName.indexOf(':') + 1) //app1、app2

export default defineConfig({
  root: `./src/${appName}/`,
  build: {
    rollupOptions: {
      input: {
        [appName]: path.resolve(__dirname, `src/${appName}/index.html`)
      },
      output: {
        chunkFileNames: 'js/[name]-[hash].js',
        entryFileNames: 'js/[name]-[hash].js',
        assetFileNames: '[ext]/[name]-[hash].[ext]',
      }
    }
  }
})


测试项目的运行和打包构建

打包构建

pnpm build:app1
pnpm build:app2

自动化生成项目基础模版

基于多入口打包,也就是一个代码库同时维护多个同类型的项目情况下,可以通过配置实现自动化生成项目基础模板,这样,当需要在代码库新建一个新项目时,可以通过命令行快速创建

前置工具

inquirer

这个插件用来询问用户输入项目名称,这是一个比较在处理命令行交互比较常见的库

主要用于实现命令行交互式界面。帮助我们与用户进行交互式交流

它有几个特点:提供错误反馈,询问问题,解析输入,验证答案

详细可参考 命令行交互工具inquirer

安装

pnpm add  inquirer@^8.0.0 -S


配置过程

在package.json里添加

"scripts": {
    "init-app": "node ./src/utils/initApp/index.ts"
}


当执行这个命令时,会自动去执行,在本地utils文件夹下的initApp文件里的js脚本,在src目录下会自动生成一个新的文件夹(项目)

在utils下新增initApp文件夹以及index.ts和temlate

在index.ts添加以下代码

#!/usr/bin/env node
console.log('您正在创建项目')
const path = require('path')
const fs = require('fs')
const inquirer = require('inquirer')
const stat = fs.stat
const targetDir = path.resolve(__dirname, './template')
//复制文件目录
const copyFile = (targetDir, resultDir) => {
  // 读取文件、目录
  fs.readdir(targetDir, function (err, paths) {
    if (err) {
      throw err
    }
    paths.forEach(function (p) {
      const target = path.join(targetDir, '/', p)
      const res = path.join(resultDir, '/', p)
      let read
      let write
      stat(target, function (err, statsDta) {
        if (err) {
          throw err
        }
        if (statsDta.isFile()) {
          read = fs.createReadStream(target)
          write = fs.createWriteStream(res)
          read.pipe(write)
        } else if (statsDta.isDirectory()) {
          fs.mkdir(res, function () {
            copyFile(target, res)
          })
        }
      })
    })
  })
}

const question = [
  {
    type: 'input',
    name: 'name',
    message: '请输入项目名称:'
  }
]

const createProject = () => {
  // 询问用户问题
  inquirer
    .prompt(question)
    .then(({ name }) => {
      // name 为输入的项目名称
      name = name.trim()
      if (!name) {
        console.log('项目目录不能为空')
        // 如果输入空,继续询问
        createProject()
        return false
      }
      // 目标路径,要放在module目录下
      const resultDir = path.resolve(__dirname, '../../', name)
      // fs.access()方法用于测试文件是否存在
      fs.access(resultDir, function (err, data) {
        if (err) {
          // 创建文件
          fs.mkdir(resultDir, function (err, data) {
            if (err) {
              throw err
            }
            // 复制模版文件
            copyFile(targetDir, resultDir)
          })
          console.log(`${name} 项目已创建成功`)
        } else {
          console.log(`${name} 项目目录已存在,请输入其他名称`)
          // 不存在,继续询问
          createProject()
        }
      })
    })
    .catch((err) => {
      console.log(err)
    })
}
createProject()


注:此代码copy==> Vue3项目框架搭建封装,一次学习,终身受益【万字长文,满满干货】

在temlate文件夹下新增项目所需要的文件目录,main.ts以及App.vue是必须的,因为它是独立的项目

使用

app3项目自动生成

持久化pinia仓库数据

数据存储在缓存(内存)中,优点读写更快,可以保存任意的js类型数据和对象,比如当我们刷新浏览器的时候,数据会丢失,所以需要实现pinia持久化

持久化插件pinia-plugin-persist

安装

pnpm add pinia-plugin-persist


import { createApp } from 'vue'
import { createPinia } from 'pinia'
import piniaPersist from 'pinia-plugin-persist'

const pinia = createPinia()
pinia.use(piniaPersist)

createApp({})
  .use(pinia)
  .mount('#app')


使用

// store/use-user-store.ts
import { defineStore } from 'pinia'

export const useUserStore = defineStore('storeUser', {
  state: () => {
    return {
      firstName: 'S',
      lastName: 'L',
      accessToken: 'xxxxxxxxxxxxx'
    }
  },
  actions: {
    setToken (value: string) {
      this.accessToken = value
    }
  },
  persist: {
    enabled: true,
    //这里可以单独给每个字段配置存储的形式sessionStorage/localStorage
    //paths配置state里的字段,不同的数据采取不同的存储方式
    strategies: [
      { storage: sessionStorage, paths: ['firstName', 'lastName'] },
      { storage: localStorage, paths: ['accessToken'] },
    ],

  }
})


strategies 字段说明:

属性

描述

key

自定义存储的 key,默认是 store.$id

storage

可以指定localStorage/sessionStorage,或者自定义存储类型,默认为 sessionStorage

paths

state 中的字段名,按组打包储存

也可以自定义存储类型,更多具体配置戳pinia-plugin-persist插件官网地址

源码解析

核心是通过 store.$subscribe去监听仓库数据,当仓库数据发生变化时会触发回调,更改本地缓存数据,当刷新后就会从本地缓存取出相关的数据

import { PiniaPluginContext } from 'pinia'


type Store = PiniaPluginContext['store']; //pinia插件上下文
type PartialState = Partial<Store['$state']>;

//调用函数将仓库数据存储到本地

export const updateStorage = (strategy: PersistStrategy, store: Store) => {
  const storage = strategy.storage || sessionStorage //可以自定义存储类型,默认为sessionStorage
  const storeKey = strategy.key || store.$id   //可以自定义存储的 key,默认是 store.$id 

 //判断是否有配置paths,如果没有就缓存一整个仓库中的state
  if (strategy.paths) {
  
  //遍历paths里面的字段,并通过 store.$state[key]获取相应的数据
    const partialState = strategy.paths.reduce((finalObj, key) => {
      finalObj[key] = store.$state[key]
      return finalObj
    }, {} as PartialState)
    
    //存储到本地
    storage.setItem(storeKey, JSON.stringify(partialState))
  } else {
    storage.setItem(storeKey, JSON.stringify(store.$state))
  }
}

export default ({ options, store }: PiniaPluginContext): void => {
    //判断enabled是否为true
    
  if (options.persist?.enabled) {
    const defaultStrat: PersistStrategy[] = [{
      key: store.$id,
      storage: sessionStorage,
    }]

    const strategies = options.persist?.strategies?.length ? options.persist?.strategies : defaultStrat

    strategies.forEach((strategy) => {
      const storage = strategy.storage || sessionStorage
      const storeKey = strategy.key || store.$id
      
     //根据key判断是否在本地缓存中,如果在刷新后会从本地缓存中将数据赋给pinia仓库的state
      const storageResult = storage.getItem(storeKey)

     // 如果本地中存在同步数据,更新仓库state数据
     //(比如浏览器刷新后会进行判断,如果有数据会赋值给pinia仓库的state,实现pinia持久化)
      if (storageResult) {
        store.$patch(JSON.parse(storageResult))
        updateStorage(strategy, store)
      }
    })
    
    //通过$subscribe监听state,仓库数据更改会触发回调同步更改本地数据
    store.$subscribe(() => {
      strategies.forEach((strategy) => {
        updateStorage(strategy, store)
      })
    })
  }
}


引入nprogess进度条

通过显示进度条的形式,来提高用户体验,可用在进入/离开路由时触发动画,也可在发接口时使用

安装

pnpm add nprogress -S


基本用法

只需调用start()和done()即可控制进度条。

NProgress.start();
NProgress.done();


使用场景

切换路由

router.beforeEach((to, from, next) => {
  NProgress.start()
  next()
})
router.afterEach(() => {
  NProgress.done()
})


发请求时

// axios请求拦截器
axios.interceptors.request.use(
config => {
    NProgress.start() // 设置加载进度条(开始..)
    return config
},
error => {
    return Promise.reject(error)
}
)
// axios响应拦截器
axios.interceptors.response.use(
function(response) {
    NProgress.done() // 设置加载进度条(结束..)
    return response
},
function(error) {
    return Promise.reject(error)
}
)


其它详细配置请戳官网:ricostacruz.com/nprogress/

viewport 适配方案 - postCSS插件

介绍

PostCSS 是一种 JavaScript 工具,可将你的 CSS 代码转换为抽象语法树 (AST),然后提供 API(应用程序编程接口)用于使用 JavaScript 插件对其进行分析和修改。

Autoprefixer主要功能是解析CSS并使用Can I Use中的值向CSS规则添加供应商前缀。以兼容各种浏览器,部分CSS属性需要加上不同的前缀以兼容不同的浏览器。通过配置Autoprefixer,自动为CSS属性添加对应浏览器的前缀。

postcss-px-to-viewport 用于将单位为 px 的尺寸转换为视口单位(vw, vh, vmin, vmax)

下面用到Autoprefixer和postcss-px-to-viewport这两个插件进行viewport适配

PostCSS 配置

安装

pnpm add postcss-px-to-viewport -D
pnpm add  autoprefixer -D


创建postcss.config.js并配置

// postcss.config.js
module.exports = () => {
  return {
    plugins: {
      autoprefixer: {},
      'postcss-px-to-viewport': {
        unitToConvert: 'px', // 需要转换的单位,默认为"px"
        viewportWidth: 1920, // 设计稿的视口宽度
        unitPrecision: 5, // 单位转换后保留的精度
        propList: ['*'], // 能转化为vw的属性列表
        viewportUnit: 'vw', // 希望使用的视口单位
        fontViewportUnit: 'vw', // 字体使用的视口单位
        selectorBlackList: [], // 需要忽略的CSS选择器,不会转为视口单位,使用原有的px等单位。
        minPixelValue: 1, // 设置最小的转换数值,如果为1的话,只有大于1的值会被转换
        mediaQuery: false, // 媒体查询里的单位是否需要转换单位
        replace: true, //  是否直接更换属性值,而不添加备用属性
        exclude: undefined, // 忽略某些文件夹下的文件或特定文件,例如 'node_modules' 下的文件
        include: undefined, // 如果设置了include,那将只有匹配到的文件才会被转换
        landscape: false, // 是否添加根据 landscapeWidth 生成的媒体查询条件 @media (orientation: landscape)
        landscapeUnit: 'vw', // 横屏时使用的单位
        landscapeWidth: 1920 // 横屏时使用的视口宽度
      }
    }
  }
}


效果如下

不同视口宽度,界面会响应性变化


作者:小希学前端
链接:https://juejin.cn/post/7327965216826032154

相关推荐

恢复软件6款汇总推荐,帮你减轻数据恢复压力!

在当今数字化生活中,数据丢失的风险如影随形。无论是误删文件、硬盘故障,还是遭遇病毒攻击,丢失的数据都可能给我们带来不小的麻烦。此时,一款优秀的数据恢复软件就成为了挽救数据的关键。今天,为大家汇总推荐...

中兴星星一号刷回官方原版recovery的教程

【搞科技教程】中兴星星一号的官方recovery也来说一下了,因为之前给大家分享过了第三方的recovery了,之前给大家分享的第三方recovery也是采用一键刷入的方式,如果细心的朋友会发现,之前...

新玩机工具箱,Uotan柚坛工具箱软件体验

以前的手机系统功能比较单调,各厂商的重视程度不一样,所以喜欢玩机的朋友会解锁手机系统的读写权限,来进行刷机或者ROOT之类的操作,让使用体验更好。随着现在的手机系统越来越保守,以及自身功能的增强,...

三星g906k刷recovery教程_三星g906k中文recovery下载

【搞科技教程】看到有一些机友在找三星g906k的第三方recovery,下面就来说一下详细的recovery的刷入方法了,因为手机只有有了第三方的recovery之后才可以刷第三方的root包和系统包...

中兴星星2号刷recovery教程_星星二号中文recovery下载

【搞科技教程】咱们的中兴星星2手机也就是中兴星星二号手机的第三方recovery已经出来了,并且是中文版的,有了这个recovery之后,咱们的手机就可以轻松的刷第三方的系统包了,如果没有第三方的re...

数据恢复软件有哪些值得推荐?这 6 款亲测好用的工具汇总请收好!

在数字生活中,数据丢失的阴霾常常突如其来。无论是误删工作文档、格式化重要磁盘,还是遭遇系统崩溃,都可能让我们陷入焦虑。关键时刻,一款得力的数据恢复软件便是那根“救命稻草”。今天,为大家精心汇总6...

中兴u956刷入recovery的教程(中兴e5900刷机)

【搞科技教程】这次主要来给大家说说中兴u956手机如何刷入第三方的recovery,因为第三方的recovery工具是咱们刷第三方rom包的基础,可是很我欠却不会刷,所以太这里来给大家整理了一下详细的...

联想A850+刷recovery教程 联想A850+第三方recovery下载

【搞科技教程】联想A850+的第三方recovery出来了,这个第三方的recovery是非常的重要的,比如咱们的手机要刷第三方的系统包的时候,都是需要用到这个第三方的recovery的,在网上也是有...

工具侠重大更新 智能机上刷机一条龙完成

工具侠是针对玩机的机油开发的一款工具,不管是发烧级别的粉丝,还是普通小白用户,都可以在工具侠上找到你喜欢的工具应用。这不,最新的工具侠2.0.16版本,更新了专门为小白准备的刷机助手工具,以及MTK超...

shift+delete删除的文件找回6种硬盘数据恢复工具

硬盘作为电脑的重要存储设备,如同一个巨大的数字仓库,承载着我们日常工作、学习和生活中的各种文件,从珍贵的照片、重要的工作文档到喜爱的视频、音乐等,都依赖硬盘来安全存放。但有时,我们可能会不小心用sh...

使用vscode+Deepseek 实现AI编程 基于Cline和continue

尊敬的诸位!我是一名专注于嵌入式开发的物联网工程师。关注我,持续分享最新物联网与AI资讯和开发实战。期望与您携手探寻物联网与AI的无尽可能。这两天deepseek3.0上线,据说编程能力比肩Cl...

详解如何使用VSCode搭建TypeScript环境(适合小白)

搭建Javascript环境因为TypeScript不能直接在浏览器上运行。它需要编译器来编译并生成JavaScript文件。所以需要首先安装好javascript环境,可以参考文章:https://...

使用VSCode来书写你的Jupyter Notebooks

现在你可以在VScode里面来书写你的notebook了,使用起来十分的方便。下面来给大家演示一下环境的搭建。首先需要安装一个jupyter的包,使用下面的命令安装:pip3install-ih...

使用VSCode模板提高Vue开发效率(vscode开发vue插件)

安装VSCode安装Vetur和VueHelper插件,安装完成后需要重启VScode。在扩展插件搜索框中找到如下Vetur和VueHelper两个插件,注意看图标。添加Vue模板打...

干货!VsCode接入DeepSeek实现AI编程的5种主流插件详解

AI大模型对编程的影响非常之大,可以说首当其冲,Cursor等对话式编程工具渐渐渗透到开发者的工作中,作为AI编程的明星产品,Cursor虽然好用,但是贵啊,所以咱们得找平替,最好免费那种。俗话说,不...