无构建和打包,浏览器直接吃上Vue全家桶?

Vue 是易学易用,性能出色,适用场景丰富的 Web 前端渐进式框架;常用来开发单页面应用。

主流开发方式-编译打包

用脚手架工具 create-vue 可以快速通过 npm create vue@latest命令 来定制化新建一个 Vite 驱动的 Vue 单页面应用项目。

这是常规的使用 Vue 的方式。当然也可以从 Vite 那边入手。

我们新建一个项目 vue-demo来试试,选上 Vue-Router 和 Pinia, 其余的不选: 访问 http://localhost:5173/, 正常打开: 初始化的模板,用上了 Vue-Router,有两个路由, '/', '/about';那 Pinia 呢?可以看到依赖已经安装了引入了,给了一个 demo 了 我们来用一下 Pinia, 就在about路由组件里面用下吧:

html 复制代码
<script setup>
import { useCounterStore } from '@/stores/counter'
import { storeToRefs } from 'pinia'
const store = useCounterStore()
const { count, doubleCount } = storeToRefs(store)
const { increment } = store
</script>

<template>
  <div class="about">
    <h1>{{ count }}</h1>
    <h1>{{ doubleCount }}</h1>
    <button @click="increment">+1</button>
  </div>
</template>

<style>
@media (min-width: 1024px) {
  .about {
    min-height: 100vh;
    display: flex;
    align-items: center;
  }
}
</style>

这就是 Vue + Vue-Router + Pinia 全家桶在 打包构建工具 Vite 驱动下的开发方式。 Vite 开发阶段不打包,但会预构建项目的依赖,需要哪个资源会在请求的时候编译,而项目上线则需要打包。

完美对吧!但你有没有注意到,官网除了介绍这种方式,还介绍了 "Using Vue from CDN": 也就是说,可以 HTML 文件里面直接用上 Vue 的对吧?那我还想要 Vue-Router、 Pinia、Axios、 Element-Plus 呢?怎么全部直接用,而不是通过npm install xxx 在需要构建打包的项目里面用?

如何直接吃上 Vue 全家桶

我们将会从一个 HTML 文件开始,用浏览器原生的 JavaScript modules 来引入 Vue 、引入 Vue-Router,、引入 Pinia、引入 Axios, 并且构建一个类似工程化的目录结构,但不需要打包,JS 是 ES modules 语法;而项目的运行,只需要用npx serve -s在当前项目目录起一个静态文件服务器,然后浏览器打开即可。

HTML 文件引入 Vue

找个空文件夹,我们新建一个 index.html: 把 Vue 文档代码复制过来:

html 复制代码
<script type="importmap">
  {
    "imports": {
      "vue": "https://unpkg.com/vue@3/dist/vue.esm-browser.js"
    }
  }
</script>

<div id="app">{{ message }}</div>

<script type="module">
  import { createApp, ref } from 'vue'

  createApp({
    setup() {
      const message = ref('Hello Vue!')
      return {
        message
      }
    }
  }).mount('#app')
</script>

当前目录下执行下npx serve -s打开看看

没问题。

但是经常写页面的朋友都知道,肯定得拆分组件,不然全写一个页面不好维护,这点官网也给了例子: 照猫画虎,我们拆分一下:

新建 src/app.js文件,如下内容:

js 复制代码
import { ref } from 'vue'
export default {
  setup() {
    const count = ref(0)
    return { count }
  },
  template: `<div @click="count++">Count is: {{ count }}</div>`
}

然后在 index.html引入:

js 复制代码
<script type="module">
  import { createApp, ref } from 'vue'
  import App from './src/app.js'

  createApp(App).mount('#app')
</script>

刷新下页面看看: Vue 成功引入并使用了。但还有遗憾,就是app.js"组件"的 template 部分是字符串,没有高亮,不利于区分: 关于这点,官网也说了,如果你使用 VS Code, 那你可以安装插件 es6-string-html,用 /*html*/实现高亮: 我们来试试看: 至此,我们可以相对舒服地使用 Vue 进行组件开发了。

HTML 文件引入、Vue 集成 Vue-Router

项目如果有不同的页面,就需要 Vue-Router 了, Vue-Router官网同样有网页直接引入的介绍: 我们来试一下,先在 Import Maps 添加 vue-router 的引入: 然后写个使用 Vue-router 的demo: 新建两个路由组件:src/view/home.js, src/view/about.js, 在 HTML 文件中引入: src/app.js作为根组件,放个 RouterLink、RouterView组件: 然后我们刷新下页面,看看是否正常生效: 很遗憾,没有生效,控制台报错了: 意思是声明的vue-router模块,没有导出我们引用到的方法 createRouter;这说明,Vue-Router打包的默认文件,并不是默认的 ES Modules 方式,我们得找找对应的构建产物文件才行;

这对比Vue的引入,Vue引入的是构建产物中的 "esm-browser" 后缀的文件: 那么斗胆猜测下,Vue-Router同样也有 esm 的构建产物,我们引入下该文件,应该就可以了。

但是怎么知道Vue-Router的构建产物有哪些?难道去翻官方的构建配置吗?不用,我们找个npm项目,然后npm install vue-router,在 node_mudules/xxx翻看就知道了。

我们上面正好有个 vue-demo, 使用了Vue-Router。我们看看: 我们改下 Import Maps 里面 vue-router 的映射: 刷新下页面看看: 还是有报错: @vue/devtools-api我们并没有引入,报了这个错,斗胆猜测是 vue-router 中使用的,该模块应该是属于外部模块,我们看看网络里面响应的文件验证下: 确实如此,那么 Import Maps 也补充下引入这个模块,我们先翻看该模块的 npm 包看看,确定下路径: Import Maps 里面引入: 再刷新下页面试试: 至此,我们成功地在 HTML 文件中引入,在 Vue 中集成了 Vue-Router。

下面我们来看 Pinia 的

但在这之前,我们来整理下现在的目录划分吧。

新建 src/router/index.js 文件,将路由相关的逻辑放到这里: index.html引入 router: 然后type=module 的 script 里面的内容也可以抽离出来到单独的文件里面: 新建 main.js 文件,将内容搬过去并引入: 页面刷新下,正常运行。

HTML 文件引入、Vue 集成 Pinia

有了上面引入 Vue-Router 的经验,我们就知道了,引入其他的库也是相同的套路。我们去之前的脚手架工具生成的项目 vue-demo 的依赖里面翻看一下,Pinia 包的构建产物是如何的,然后在现在的 esm 项目里面引入吧:

我们在项目里面使用一下 Pinia, 在main.js里面引入 Pinia:

js 复制代码
import { createApp, ref } from 'vue'
import App from './src/app.js'
import router from './src/router/index.js'
import { createPinia } from 'pinia'

const app = createApp(App)
app.use(createPinia())
app.use(router)
.mount('#app')

新建 src/stores/useCounterStore.js文件,填入如下内容:

js 复制代码
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'

export default defineStore('counter', () => {

  const count = ref(0)
  const doubleCount = computed(() => count.value * 2)
  const increment = () => {
    count.value++
  }
  return { count, doubleCount, increment }
})

即如下: 之后我们在 src/view/home.js组件里面使用一下这个 store:

js 复制代码
import useCounterStore from "../stores/useCounterStore.js"
import { storeToRefs } from 'pinia'

export default {
  setup() {
    const store = useCounterStore()
    const { count, doubleCount } = storeToRefs(store)
    const { increment } = store
    return { count, doubleCount, increment }
  },
  template: /*html*/`<div>
    <h1>Home</h1>
    <p>{{ count }}</p>
    <p>{{ doubleCount }}</p>
    <button @click="increment">+1</button>
  </div>`
}

我们刷新页面看看,报错了, 缺了一个模块 vue-demi 我们确认一下,在响应的 Pinia 库中确实有对这模块的引入 那么我们也引入一下吧,我们翻看需要的库的文件路径,注意这里的 esm 模块是 .mjs 后缀文件 再刷新看看: 至此,我们就在 HTML 文件中直接引入 Vue, 集成了 Vue-Router、Pinia。

HTML 文件引入 Axios

接下来,我们来看看网络请求库 Axios

网络请求, 原生的 fetch API 可以胜任,但是对于项目的网络请求,最好有统一的拦截器处理,而Axios已经有了一套可行的方案,所以我项目开发一般会用 Axios。本节不讲Axios封装,只介绍在原生 HTML 文件中直接引入和使用 Axios。

要以 ESM 方式引入 Axios,我们得知道 Axios esm 模块的路径。我们在上述的工程化项目vue-demo中安装和查看路径 我们在 Import Maps 添加引入 我们添加 src/mock/test.json文件,里面存放JSON 数据,然后用 axios 请求试试看: 我们在 src/view/about.js组件里面使用一下 Axios 来获取 mock 数据,并且显示到页面上,代码如下:

js 复制代码
import axios from 'axios'
import { ref } from 'vue'

export default {
  setup() {
    const mockData = ref(null)
    axios.get('/src/mock/test.json').then(res => {
      mockData.value = res.data
    })
    return { mockData }
  },
  template: /*html*/`<div>
    <h1>About</h1>
    <pre>
    {{ mockData }}
    </pre>
  </div>`
}

刷新看看: 没有问题,可以正常使用,至于 Axios 如何封装得适合项目,这里就不展开了。

CSS 样式解决方案

但目前为止,我们几乎没有写样式,但这种纯 ESM 项目,我们应该怎么写样式呢?

用打包构建工具的项目,一般都有 CSS 的预构建处理工具,比如 Less, Scss等;但实际开发中,大部分就使用一下嵌套而已;

现在最新的浏览器已经支持 CSS 嵌套了: 还有 CSS 模块化的兼容性也完全没问题: 那么此 ESM 项目我这里给一个建议的方案,读者欢迎评论区留言提供其他方案。

新建 src/style/index.css 文件,键入如下样式:

css 复制代码
body {
  background-color: aqua;
}

index.html文件中引入该样式: 刷新看看是否生效 项目中该怎么进行组件的 CSS 样式隔离呢?这里就建议 采用 ESM 的类名样式方案咯,这里不展开讲,只给一个样式目录参考。建议如下: 将样式放在 src/style下面,按照组件的目录进行放置,然后在src/style/index.css引入: 效果如下:

样式中,我使用了CSS模块化语法和嵌套语法,都生效了。

HTML 文件引入、Vue 集成 Element-Plus

最后,我们再引入组件库吧。我这里使用 Element-Plus

官网可以看到也是支持直接引入的,要注意的是得引入其样式 我们在上面工程化项目 vue-demo 里面安装下 Element-Plus 的 npm 包看看 esm 文件的位置(.mjs后缀文件一般就是esm模块): index.html 文件里面引入样式,在 Import Maps 里面引入 element-plus: 然后在 main.js 里把所有 element-plus 组件注册为全局组件并在 src/view/home.js使用下 Button 组件: 效果如下: 至此,我们在项目中集成了 Element-Plus 组件库了。

总结

我们先按照 Vue 官方文档使用了常规的项目开发方式创建了一个项目。

然后我们提出了一个想法:能否直接在 HTML文件中使用 Vue 及其全家桶?

答案是可行的,因为几乎所有的库都提供了 ESM 的构建文件,而现今的浏览器也都支持 ESM 模块化了。

我们也探讨和实践了 CSS 模块化 和 CSS 嵌套,用在了 demo 中作为 esm 项目的样式方案。

最后我们在项目中集成了 Element-Plus 组件库。

至此,我们可以点题了:无打包构建,浏览器确实能吃上 Vue 全家桶了。但这并不是说,可以在真实项目中这样使用,兼容性就不说了,还有项目的优化,一般得打包构建中做:比如 Tree Shareing、代码压缩等。但如果是一些小玩具项目,可以试试这么玩。无构建和打包,浏览器跑的代码就是你写的源码了。

本文示例代码地址:gitee.com/GumplinGo/1...

相关推荐
F-2H42 分钟前
C语言:指针4(常量指针和指针常量及动态内存分配)
java·linux·c语言·开发语言·前端·c++
苹果酱05671 小时前
「Mysql优化大师一」mysql服务性能剖析工具
java·vue.js·spring boot·mysql·课程设计
gqkmiss1 小时前
Chrome 浏览器插件获取网页 iframe 中的 window 对象
前端·chrome·iframe·postmessage·chrome 插件
m0_748247553 小时前
Web 应用项目开发全流程解析与实战经验分享
开发语言·前端·php
m0_748255024 小时前
前端常用算法集合
前端·算法
真的很上进4 小时前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html
web130933203984 小时前
vue elementUI form组件动态添加el-form-item并且动态添加rules必填项校验方法
前端·vue.js·elementui
NiNg_1_2345 小时前
Echarts连接数据库,实时绘制图表详解
前端·数据库·echarts
如若1235 小时前
对文件内的文件名生成目录,方便查阅
java·前端·python
滚雪球~6 小时前
npm error code ETIMEDOUT
前端·npm·node.js