vue 时间插件_Vue3.0:编写一个Vite插件

781bfc2c7b01447afc2d3cfde6a09c85.png

| 来源:公众号《前端全栈开发者》

随着Vue 3最近进入发布候选阶段,是你尝试一下的绝佳时机。要马上开始,你需要使用vite,Vue的创建者提供的新的web开发构建工具。Vite提供了一个新的插件系统来扩展Vite的功能。今天我们来看看如何设置一个简单的vite插件。


Vue3系列文章:

  • 迎接Vue3.0系列 | Vue3中的Vue Router初探
  • 迎接Vue3.0系列 | 如何在Vue2与Vue3中构建相同的组件
  • Vue 3教程(适用于Vue 2用户)
  • 迎接Vue3.0系列 | Vue3 Composition API中的提取和重用逻辑
  • 迎接Vue3.0系列 | 如何在Vue3中使用生命周期钩子函数
  • Vue 3升级指南,升级没那么难
  • 准备迎接Vue3,使用Vue Composition API生成干净可扩展的表单

这个插件会做什么?

我们的插件将根据Vue组件的目录自动生成Vue-Router路由。这从Nuxt的路由功能得来的灵感,即我们想把这个目录结构:

src/|-- pages/    |-- about.vue    |-- contact.vue

自动进入以下路由:

[  {    name: 'about',    path: '/about',    component: '/src/pages/about.vue'  },  {    name: 'contact',    path: '/contact',    component: '/src/pages/contact.vue'  },]

关于vite

/ 什么是vite?/

vite 是一个基于 Vue3 单文件组件的非打包开发服务器,Vite提供了比vue-cli和其他基于webpack的设置更快的构建时间。它做到了本地快速开发启动:

  1. 快速的冷启动,不需要等待打包操作;
  2. 即时的热模块更新,替换性能和模块数量的解耦让更新飞起;
  3. 真正的按需编译,不再等待整个应用编译完成,这是一个巨大的改变。

/ Vite插件概念 /

在撰写本文时,还没有真正的文档来创建vite插件。vite仓库自述文件中讨论了一些概念,但是你需要在vite源代码中进行一些挖掘,以确切地了解如何编写插件。让我们讨论一些关键概念。

dev server:当涉及到javascript时,现代浏览器可以处理(某种程度上)ES模块导入,但是如果遇到其他文件类型的导入则不能。每次浏览器在代码中找到导入时,它将先通过vite的开发服务器,然后直接提供给浏览器。这些导入可以是javascript,vue,css——如果你告诉vite如何处理它,则可以是任何东西。这就是为什么Vite开发服务器如此有用的原因——它为你解决了该浏览器的限制。

rollup production bundle:对于静态内容,你不需要在生产构建中使用vite dev服务器。因此,vite使用rollup将你的代码捆绑用于生产。

Vue自定义块转换:有时你使用的其他库会让你在vue文件中添加自定义块,比如 。Vite让你指定遇到这些块时如何处理。

编写我们的插件

我们采用的一般方法是自动生成一个 vue-auto-routes.js 文件,然后从中导出路由数组。我们将把该文件视为虚拟文件,该文件是在运行时(对于开发服务器)和构建时(对于汇总)动态生成的。然后,我们可以在我们的代码中导入这些路由,并在我们的应用程序中使用它们。

/ 自动生成vue-router路由 /

为了填充我们的 vue-auto-routes.js 文件,我们需要解析我们的 src/pages 目录,并把它变成一些导入语句和一个路由数组。我们将粗略地使用内置的 fs Node模块执行此操作:

function parsePagesDirectory() {  const files = fs    .readdirSync('./src/pages')    .map((f) => ({ name: f.split('.')[0], importPath: `/src/pages/${f}` }))  const imports = files.map((f) => `import ${f.name} from '${f.importPath}'`)  const routes = files.map(    (f) => `{        name: '${f.name}',        path: '/${f.name}',        component: ${f.name},      }      `,  )  return { imports, routes }}

我们从该函数返回两个列表:

  • imports:我们的导入语句列表,例如“import about from 'src/pages/about.vue'”
  • routes:我们的路由数组,例如“{ name: 'about', path: '/about', component: about }”

请记住,现在这些是字符串,因为我们正在使用它们创建一个javascript文件。请注意,对于路由数组中的组件,我们使用导入的变量,而不是字符串或动态组件——你将在后面看到原因。

/ 创建一个空插件 /

Vite插件只是一个添加了各种选项的对象。我们将很快开始添加这些选项。让我们创建一个实际上可以用作插件的javascript文件:

module.exports = function() {  return {}}

然后,我们可以在 vite.config.js 中使用它,如下所示:

const viteAutoRoute = require('./plugin.js')module.exports = {  plugins: [viteAutoRoute()],}

我们使用一个函数而不只是一个普通的对象,以便将来我们可以向插件添加自己的自定义选项。例如,也许我们想使用 viteAutoRoute({ pagesDir: './src/docs' }) 之类的名称指定自定义页面目录。

/ 为本地开发开辟道路 /

现在让我们实际利用我们之前创建的那些路由。为此我们将使用 configureServer vite插件选项。

module.exports = function () {  const { imports, routes } = parsePagesDirectory()  const moduleContent = `    ${imports.join('')}    export const routes = [${routes.join(', ')}]  `  const configureServer = [    async ({ app }) => {      app.use(async (ctx, next) => {        if (ctx.path.startsWith('/@modules/vue-auto-routes')) {          ctx.type = 'js'          ctx.body = moduleContent        } else {          await next()        }      })    },  ]    return { configureServer }}

首先,我们创建一个字符串 moduleContent,其中包含路由javascript文件的所需内容。然后,我们创建 configureServer ——将用作vite开发服务器中的附加中间件的函数列表。每当vite在你的javascript或vue文件中遇到导入时,它就会向其开发服务器发出请求,在必要时进行一些转换,然后以浏览器可以处理的形式发送回来。

当它遇到类似 import { routes } from 'vue-auto-routes' 这样的东西时,它将会发出 @/modules/vue-auto-routes 的请求。因此,我们要做的是拦截该请求,并将生成的 moduleContent 作为正文返回,并将其声明为 js 类型。

最后,我们将此 configureServer 数组添加到返回的对象中,以供Vite使用。Vite将看到这一点,并将我们的清单(共1个)中间件与自己的中间件合并。现在,我们可以在自己的路由器中使用这些动态生成的路由:

import { createApp } from 'vue'import { createRouter, createWebHashHistory } from 'vue-router'import { routes } from 'vue-auto-routes'import App from './App.vue'const router = createRouter({  history: createWebHashHistory(),  routes,})createApp(App).use(router).mount('#app')

现在,当我们运行 yarn dev 时,我们的路由将起作用,例如http://localhost:3000/#/about

请注意,我们使用的是vue-router-next——Vue 3即将推出的路由器。

/ 在生产版本中访问我们的路由 /

当我们运行 yarn build 时,它不会查看我们刚刚制作的 configureServer 东西,因为它使用rollup而不是vite的dev服务器。因此,我们需要添加一些其他配置以使其在生产中正常工作:

const virtual = require('@rollup/plugin-virtual')module.exports = function () {  // 我们之前的moduleContent和configureServer ...  const rollupInputOptions = {    plugins: [virtual({ 'vue-auto-routes': moduleContent })],  }  return { configureServer, rollupInputOptions }}

在这里,我们使用 rollupInputOptions vite插件选项,这使我们可以传递rollup插件。我们使用 @rollup/plugin-virtual 来获取模块名称,并让你返回所需的任何javascript内容。本质上与开发服务器解决方案做相同的事情。

现在,我们的路由将在本地开发和生产中都起作用。

/ 添加自定义块 /

各个Vue页面可能希望为其所对应的路由提供其他选项。例如,我们可能想要向我们的路由添加一些其他元选项,或使用自定义路由名称。为此,我们将重新实现 vue-cli-plugin-auto-routing 的路由块,以便在vue组件中执行以下操作:

{  "meta": {    "requiresLogin": true,  }}

为此,我们将使用 vueCustomBlockTransforms 选项,这允许你告诉vite在遇到vue文件中的自定义块时如何处理它们。由于这是我们要添加的最后一件事,因此让我们将其作为整个插件的一部分来看一下:

const fs = require('fs')const virtual = require('@rollup/plugin-virtual')function parsePagesDirectory() {  const files = fs    .readdirSync('./src/pages')    .map((f) => ({ name: f.split('.')[0], importPath: `/src/pages/${f}` }))  const imports = files.map((f) => `import ${f.name} from '${f.importPath}'`)  const routes = files.map(    (f) => `{        name: '${f.name}',        path: '/${f.name}',        component: ${f.name},        ...(${f.name}.__routeOptions || {}),      }      `,  )  return { imports, routes }}module.exports = function () {  const { imports, routes } = parsePagesDirectory()  const moduleContent = `    ${imports.join('')}    export const routes = [${routes.join(', ')}]  `  const configureServer = [    async ({ app }) => {      app.use(async (ctx, next) => {        if (ctx.path.startsWith('/@modules/vue-auto-routes')) {          ctx.type = 'js'          ctx.body = moduleContent        } else {          await next()        }      })    },  ]  const rollupInputOptions = {    plugins: [virtual({ 'vue-auto-routes': moduleContent })],  }  const vueCustomBlockTransforms = {    route: ({ code }) => {      return `        export default function (Component) {          Component.__routeOptions = ${code}        }      `    },  }  return { configureServer, rollupInputOptions, vueCustomBlockTransforms }}

我们已经添加了一个 vueCustomBlockTransforms 对象,该对象将关键 route(我们的块名)映射到一个函数,该函数本质上是返回另一个虚拟javascript文件。它有一个默认的导出函数,它为相关的 vue 文件取了一个组件,并添加了一个我们选择的额外字段 __routeOptions,它映射到我们在任何自定义 块中声明的代码。

然后,我们在路由生成代码中使用它 ( ...(${f.name}.__routeOptions || {}) ),并将其与特定路由的其他设置合并。这就是为什么我们在虚拟的 vue-auto-routes 文件中导入组件的原因——因此我们可以访问已添加的 __routeOptions 字段。

现在,我们可以在vue页面组件中使用 $route.meta.requiresLogin 之类的东西!

/ 未来的工作 /

我们希望在不久的将来发布这个插件的更完整的版本,增加更多的功能,比如改进的热重载,自动路由参数,嵌套路由等等。你可以在这里看到很早的开始。

结束

希望你已经了解了Vite的工作原理以及如何编写一些基本的插件。请留意Vue在不久的将来正式发布的V3版本,希望他们会提供更多关于你可以使用vite插件做的其他事情的文档。

#vue3# #Vue.js#

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值