首页 > 其他分享 >使用 vue 渲染静态模板

使用 vue 渲染静态模板

时间:2023-09-05 21:11:25浏览次数:39  
标签:vue const 渲染 await rollup bundle import 模板

最近再一次需要做纯静态页面(无任何脚本语言,只保留 css 和 html),以往我直接使用 ejs 生成,但是工作中一直使用 jsx 和 vue 来组装页面,就突发奇想,难道 react、vue 不能只渲染纯静态页面吗?

有了这个想法,我就想验证下可行性,万能百度开始,找了一圈,发现基本都是需要脚本依赖的,这就意味着必须引入 react 或者 vue,而我只是想纯粹地想渲染纯页面,压根不需要脚本。或许是我搜索的姿势不对,最后没有找到合适的插件,那就自己组装一个。

说干就干,首先我需要说明下编译环境的要求,可以读写文件,可以运行 js 脚本,选择 node 还是 deno,看你自己,我选择的是 node(用的太多了),版本需要 >= 16,依赖库选择的是 vue3,准备好了,那就可以开始了。

直接找 vue3 源码阅读,发现在 server-renderer 包中的 README.md 中,作者已经贴出示例代码:

const { createSSRApp } = require('vue')
const { renderToString } = require('@vue/server-renderer')

const app = createSSRApp({
  data: () => ({ msg: 'hello' }),
  template: `<div>{{ msg }}</div>`
})

;(async () => {
  const html = await renderToString(app)
  console.log(html)
})()

那就要围绕这个开始,我本身有自己的需求,单独的 vue 文件和 css 注入,首先需要编译单独的 vue 文件,而不是 template 字符串,源码中看到 compiler-sfc ,在阅读之后,发现它就是 .vue 文件转换器,我们可以找到插件 rollup-plugin-vue 来编译 .vue 文件,对照着 rollup 官网,直接祭出以下代码:

import { rollup } from 'rollup'
import vue from 'rollup-plugin-vue'

const bundle = await rollup({
  input: 'src/index.js',
  plugins: [
    vue({ target: 'node' })
  ]
})
await bundle.write({
  format: 'es', // 这里是为了配合 node,后续会说到
  file: 'cache.tmp.js'
})

if (bundle) {
  await bundle.close()
}

这样基本就算打包成功了,但是会有个警告,就是 external 需要我们处理下,查看了下编译之后的代码,发现其依赖 2 个包 vuevue/server-rendered,其实就是 vue3 的包,我们稍微修改下:

import { rollup } from 'rollup'
import vue from 'rollup-plugin-vue'

const bundle = await rollup({
  input: 'src/index.js',
+ external: ['vue', 'vue/server-renderer'],
  plugins: [
    vue({ target: 'node' })
  ]
})
await bundle.write({
  format: 'es', // 这里是为了配合 node,后续会说到
  file: 'cache.tmp.js'
})

if (bundle) {
  await bundle.close()
}

这时候警告没有,将 vue 文件编译成 js 文件成功,接下来就是样式,直接找到对应的插件,rollup-plugin-postcssrollup-plugin-scssrollup-plugin-sassrollup-plugin-less 等(太多了,自己选择),我使用的是 rollup-plugin-less, 重新调整代码:

import { rollup } from 'rollup'
import vue from 'rollup-plugin-vue'
+ import less from 'rollup-plugin-less'

const bundle = await rollup({
  input: 'src/index.js',
  external: ['vue', 'vue/server-renderer'],
  plugins: [
    vue({ target: 'node' }),
+   less({ output: 'cache.tmp.css' })
  ]
})
await bundle.write({
  format: 'es', // 这里是为了配合 node,后续会说到
  file: 'cache.tmp.js'
})

if (bundle) {
  await bundle.close()
}

到这里,基本上 css 和 js 都准备好了,原材料准备好,我们就可以开始组装纯静态网页了。在此之前,我们需要准备一个 html 模板,可以是单独的文件,这样直接使用 fs.readFile 读取内容,也可以使用字符串,我直接选择字符串,代码如下:

const htmlTemplate = `
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>$css</style>
</head>
<body>
  <div data-ssr="true">$ssr</div>
</body>
</html>
`.trimStart()

这里面有 2 个占位符,一个是 $css,为了填充 css 代码,一个是 $ssr,为了填充 html 代码,css 代码我们直接读取刚刚生成的 css 文件即可,代码如下:

const rawCss = await fs.readFile('cache.tmp.css', 'utf-8')

html 代码,需要借助 vue 来完成转变成,代码如下:

const App = await import('./'  + 'cache.tmp.js') // import 如果绝对路径那么引入的是 node_modules 中的包
const app = createSSRApp(App.default)
const rawHtml = await renderToString(app)

这样总算是完成了最后一环,那么我们可以得到一份完整的页面字符串了,现在只需要借助 fs 模块写入即可,最后贴出完成代码(润色之后的):

import fs from 'node:fs/promises'
import { rollup } from 'rollup'
import vue from 'rollup-plugin-vue'
import less from 'rollup-plugin-less'
import { format } from 'prettier'
import { createSSRApp } from 'vue'
import { renderToString } from 'vue/server-renderer'

const OUTPUT_JS = 'cache.tmp.js'
const OUTPUT_CSS = 'cache.tmp.css'

const htmlTemplate = `
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>$css</style>
</head>
<body>
  <div data-ssr="true">$ssr</div>
</body>
</html>
`.trimStart()

const compileCode = async function() {
  const bundle = await rollup({
    input: 'src/index.js',
    external: ['vue', 'vue/server-renderer'],
    plugins: [
      vue({ target: 'node' }),
      less({ output: OUTPUT_CSS, option: { compress: true } })
    ]
  })
  await bundle.write({
    format: 'es',
    file: OUTPUT_JS
  })

  if (bundle) {
    await bundle.close()
  }
}

;(async () => {
  await compileCode()

  const App = await import('./' + OUTPUT_JS)
  const app = createSSRApp(App.default)
  const rawHtml = await renderToString(app)
  const rawCss = await fs.readFile(OUTPUT_CSS, 'utf-8')
  const html = await format(htmlTemplate.replace('$css', rawCss.trim()).replace('$ssr', rawHtml), { parser: 'html' })

  await fs.writeFile('index.html', html)
  await fs.rm(OUTPUT_CSS)
  await fs.rm(OUTPUT_JS)
})()

到此结束,有点大材小用的感觉

标签:vue,const,渲染,await,rollup,bundle,import,模板
From: https://www.cnblogs.com/blackcat/p/17680717.html

相关文章

  • 如何在Vue项目中引入富文本编辑器(wang-enduit)
    介绍官网https://www.wangeditor.com/安装yarnadd@wangeditor/editornpminstall@wangeditor/editor--saveyarnadd@wangeditor/editor-for-vue@nextnpminstall@wangeditor/editor-for-vue@next--save使用自定义上传图片,先转base64,转blob,上传服务器<divid="wa......
  • 【坑】VUE中动态数据使用 wow.js 没效果的问题
    一般来说正常使用都是在mounted函数中mounted(){this.$nextTick(()=>{this.$wow.init()})}这样如果是死数据是可以正常出现效果的但是如果是请求回来的数据是没有效果的需要改一下生成时机  此处的newList即为请求的数据watch:{newsl......
  • Vue3实现批量打印二维码与条形码
    (二维码与条形码在vue3中的使用)欢迎阅览本篇文章这篇文章是我在工作途中对批量生成二维码的一些见解,例如vue-qr(二维码)与jsbarcode(条形码)在vxe-table表格中的使用,二维码与条形码的批量生成与打印(打印时一页一个码)等。注意!本篇文章的所有代码均使用setup语法糖与TypeScript,请确保......
  • 金蝶云星空创建带分录的业务单据模板(协同开发云)
     业务对象的创建方式有新建、复制、继承三种:新建:基于空白对象创建,不受任何约束,灵活度高,元素、菜单都需要自行添加。常用于动态表单、移动业务的开发。复制:原对象复制出新的业务对象,对原对象与新对象的改动不会相互影响。常用于动态表单、移动业务的开发。继承:继承原对象的元......
  • vue3如何监听 props 的变化?
    背景实际开发过程中,当需要通过watch 监听传入的props的某个值的变化,来动态改变组件内部的样式,实现方式如下:exportdefault{name:'countdown',props:{showBox:{type:Boolean,required:true,default:false},},setup(prop......
  • vue语言中的keep-alive的作用
    在前端Vue语言中,keep-alive是一个抽象组件,用于在Vue组件树中缓存动态组件。它可以有效地保留组件的状态,以避免在组件之间切换时重复渲染和销毁组件,从而提高性能。使用keep-alive包裹动态组件后,当动态组件被切换时,它将会被缓存,而不是被销毁。这样,组件的状态、DOM以及所有的子组件......
  • 模板字符串
    点击查看代码functionrender(template,data){constreg=/\{\{(\w+)\}\}/;//模板字符串正则if(reg.test(template)){//判断模板⾥是否有模板字符串constname=reg.exec(template)[1];//查找当前模板⾥第⼀个模板字符串的字段template=template.replace(reg,......
  • vue项目新建 端口更改
    vue项目新建步骤vite创建vue3项目(最简单):在需要的文件目录中输入cmd命令,打开命令窗口,在当前文件目录下创建项目(直接打开命令窗口,默认C盘创建项目)第一步:npminitvite-appvue-code//code为项目名第二步:cd./vue-code//进入项目第三步:npminstall//安装依赖包第四......
  • vue3.0 el-table 动态合并单元格
    <el-tablev-resize:34style="margin:10px010px":data="tableData":header-cell-style="{background:'#F6F6F6',height:'10px','text-align':'center'}":......
  • antd限制开始时间与结束时间范围是30天,并不能选择当前日期之后的日期 vue3(默认展示近7
    <a-range-picker:value="hackValue||dateArr":disabled-date="disabledDate"style="width:240px"separator="~":allow-cl......