搭错车的小火柴

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

课程来源:慕课1245,笔记

1.vue3简介

1.1 课程简介

Compiler原理介绍,了解Vue3带来的性能提升,开发架构上的变化和打包编译原理。在课程实战环节中,介绍了最新的API用法、遗弃的API和升级指南。Vite作为Vue3开发环境,可以实现动态加载,冷启动 + 编译,方便开发的同时,使用rollup大幅降低了配置流程,结合Vue3的composition API,更加方便了开发。介绍了这么多,快来试试吧!

1.2 vue3的优势:

1.3 vue3.0带来的变化: 

  • 按需加载,VDom/reactive 算法,e.g. v-model/Transition
  • 组合API
  • TS 支持,
  • 新增 Fragment,不受根节点限制,渲染函数可以接受array
  • 新增Teleport,类似portal,随用随取,e.g. dialog、action
  • 新增Suspense,嵌套的异步依赖,async setup
  • 性能提升 1.3~2.X

1.4 vue-next-template-explorer 尝鲜

https://vue-next-template-explorer.netlify.app/#{"src":"<div>Hello World!</div>","options":{"mode":"module","prefixIdentifiers":false,"optimizeImports":false,"hoistStatic":false,"cacheHandlers":false,"scopeId":null,"inline":false,"ssrCssVars":"{ color }","bindingMetadata":{"TestComponent":"setup-const","setupRef":"setup-ref","setupConst":"setup-const","setupLet":"setup-let","setupMaybeRef":"setup-maybe-ref","setupProp":"props","vMySetupDir":"setup-const"}}}

示例:

  

可以看到模板中有四个div,也就是四个根节点,在vue2中,一个模板里面只能有一个根节点。编译器使用 createVNode 创建了虚拟节点,并启用 hoistStatic 能力将静态节点和动态节点区分,对静态内容,不再做更新处理。

 上面这个示例,不启用 cacheHandlers 之前是将事件绑定在当前上下文,启用了 cacheHandlers 的能力,会将事件进行全局注册。在定义组件的场景下,启用 cacheHandlers 就不会对重复创建的组件上的事件多次实例化。

ssr 模式下,抽离了静态节点,转化为string字符串。

 根据上面几个实例,可以看到 compiler 优化的几点:

  • 静态节点不在做更新处理(hoistStatic -> SSR)
  • 静态绑定的class id等属性不做更新处理
  • 结合打包hint,进行更新分析(动态绑定)
  • 事件监听器 Cache 缓存处理(cacheHandlers)
  • hoistStatic自动针对多静态节点进行优化,输出字符串
  • 按需加载,当模板为空时,输出为null

总结起来就是:

  • virtual dom机制调整
  • 内存优化
  • 按需加载,更灵活的组件化

2.vite

vite是一个http服务器,特殊的地方:

  • 可以在单文件中写es6的语法
  • 支持热更新,请求的内容才会被打包更新
  • rollup打包,按需编译

快速启动(冷启动,vite的文件放在内存里,加载更快(需要webpack去打包文件,然后去浏览器侧请求)。

vite尝试步骤:

  • 在命令行: nrm use npm
  • 在命令行:npm install -g vite
  • 在命令行:mkdir vite-demo
  • 在命令行:cd vite-demo
  • 在命令行: npm init -y
  • 新建 APP.vue  main.js 
  • 执行:vite 执行

最近找到一篇文章:vite对浏览器的请求做了什么(https://juejin.cn/post/7033713960784248868)

作者用很简单的方式讲解了vite编译的原理,自创了一个简易版的demo,很好理解,讲解了怎么实现vite的本地server、怎么编译sfc、怎么解决文件导入路径问题、怎么处理type module,当然前提是要了解vue 以及 vue compiler。

文章里 client 的 demo 实现如下:

const Koa = require('koa')
const app = new Koa()
const fs = require('fs')
const path = require('path')
const compilerSfc = require('@vue/compiler-sfc')
const compilerDom = require('@vue/compiler-dom')

// 把能读出来的文件地址变成相对地址
// 正则替换 重写导入 变成相对地址
// import { createApp } from 'vue'  => import { createApp } from '/@modules/vue'
function rewriteImport (content) {
    return content.replace(/ from ['|"](.*)['|"]/g, function (s0, s1) {
        //  s0匹配字符串,s1分组内容
        // 是否是相对路径
        if (s1.startsWith('./') || s1.startsWith('/') || s1.startsWith('../')) {
            // 直接返回
            return s0
        } else {
            return ` from '/@modules/${s1}'`
        }
    })
}

app.use(async (ctx) => {
    const { url, query } = ctx.request;
    // 处理请求资源代码都写这
    if (url === '/') {
        const p = path.join(__dirname, './index.html') // 绝对路径
        //  首页
        ctx.type = 'text/html'
        ctx.body = fs.readFileSync(p, 'utf8')
    } else if (url.endsWith('.js')) {
        // 响应js请求
        const p = path.join(__dirname, url)
        ctx.type = 'text/javascript'
        ctx.body = rewriteImport(fs.readFileSync(p, 'utf8')) // 处理依赖函数
    } else if (url.indexOf('.vue') > -1) {
        // 处理vue文件  App.vue?vue&type=style&index=0&lang.css
        // 读取vue内容
        const p = path.join(__dirname, url.split('?')[0])
        // compilerSfc解析sfc  获得ast
        const ret = compilerSfc.parse(fs.readFileSync(p, 'utf8'))
        // App.vue?type=template
        // 如果请求没有query.type 说明是sfc
        if (!query.type) {
            // 处理内部的script
            const scriptContent = ret.descriptor.script.content
            // 将默认导出配置对象转为常量
            const script = scriptContent.replace(
                'export default ',
                'const __script = ',
            )
            ctx.type = 'text/javascript'
            ctx.body = `
                ${rewriteImport(script)}
                // template解析转换为单独请求一个资源
                import {render as __render} from '${url}?type=template'
                __script.render = __render
                export default __script`
        } else if (query.type === 'template') {
            const tpl = ret.descriptor.template.content
            // 编译包含render模块
            const render = compilerDom.compile(tpl, { mode: 'module' }).code
            ctx.type = 'text/javascript'
            ctx.body = rewriteImport(render)
        } else if (url.endsWith('.png')) {
            ctx.body = fs.readFileSync('src' + url)
        }
    }
})
app.listen(3001, () => {
    console.log('dyVite start!!')
})

 

posted on 2021-01-16 10:58  搭错车的小火柴  阅读(448)  评论(0编辑  收藏  举报