likes
comments
collection
share

为开发提供极速响应的vite工作原理是怎样的呢?前言 webpack的构建原理 webpack先通过分析JavaScri

作者站长头像
站长
· 阅读数 25

前言

webpack的构建原理

vite的构建原理

那么vite的构建原理又是什么呢?大家在日常使用vite创建一个vue项目时,有没有注意到,初次创建的这个vue项目会发生很多的请求

为开发提供极速响应的vite工作原理是怎样的呢?前言 webpack的构建原理 webpack先通过分析JavaScri

这是为什么呢?原来啊对于vite而言,它会先读取到该项目的代码,然后将唯一的html文件输出给浏览器,让浏览器加载,然后加载引入JavaScript文件,此时浏览器就会向vite要JavaScript文件,vite也就会去项目中找JavaScript文件.使用vite构建工具,那么该项目的文件会被浏览器当做资源请求,将整个vue文件都做成接口请求.

手搓实现vite的工作流程

为开发提供极速响应的vite工作原理是怎样的呢?前言 webpack的构建原理 webpack先通过分析JavaScri

这是该项目的目录结构,我们使用npm init -y初始化该项目,并将vue的源码下载过来了方便使用. 我们现在目的是打造一个能实现vite工作流程一样的项目出来.创建了一个叫作simple-vite.js文件.

这里我们使用的Node.js原生所具有的模块.

const http = require('http')
const fs = require('fs')
const path = require('path')

http用于创建一个服务,fspath则是用于读取文件内容或者写文件内容以及获取文件相对应的路由.

const server = http.createServer((req, res) => {
  
})

server.listen(5173, () => {
  console.log('项目运行在 5173');
})

第一步我们在req中解构出我们发生请求的url地址,我们拿到这url,去判断是请求一个什么文件,假设请求的是根目录文件,也就是说url === '/'我们就返回唯一的html文件给浏览器.如果请求的是一个js文件,那么我们就通过path.resolve(__dirname, url.slice(1))拿到该文件的路径,然后返回给浏览器,这里我们打造了一个函数用于重构一下import引入的写法.

function rewriteImport(content) {
  return content.replace(/ from ['|"]([^'"]+)['|"]/g, function(s0, s1) {
    if (s1[0] !== '.' && s1[1] !== '/') {
      return ` from '/@modules/${s1}'`
    } else {
      return s0
    }
  })
}

变成了这样,而不是import {createApp} from "vue",这样子方便我们后续去找vue的源码使用.

为开发提供极速响应的vite工作原理是怎样的呢?前言 webpack的构建原理 webpack先通过分析JavaScri

如果url读取到的是url.startsWith('/@modules/')这样我们就需要在node_modules文件夹下找.假设这个路径是/@modules/vue为了方便我们在node_modules中查找我们就需要将/@modules/vue使用replace方法变成/vue这样我们就能准确找到该文件夹了,那么源码会在哪里呢?会在vue文件夹下的package.json中的module,将其返回给浏览器即可.

为开发提供极速响应的vite工作原理是怎样的呢?前言 webpack的构建原理 webpack先通过分析JavaScri

如果读取到的是一份vue文件的话,首先我们先获取到该文件的完整路径.我们都是找一个Vue文件是包括template,script,style三部分的,所以我们就要借助Vue.js 生态系统中的两个重要模块@vue/compiler-sfc @vue/compiler-dom,通过const { descriptor } = compilerSfc.parse(fs.readFileSync(p, 'utf8'))解析出vue文件的各个部分。然后动态生成一个JavaScript文件.并且将<template>部分的编译结果作为渲染函数导入进来。

const content = `
        ${rewriteImport(descriptor.script.content.replace('export default', 'const __script = '))} 
        import { render as __render } from "${url}?type=template" 
        __script.render = __render 
        export default __script
      `

当客户端请求带有 type=template 查询参数的 .vue 文件时,服务器会返回该文件的模板部分经过编译后的 JavaScript 代码

else if (query.get('type') === 'template') {  // 问我要 App.vue 的 template 部分
      const template = descriptor.template
      const render = compilerDom.compile(template.content, {mode: 'module'}).code
      res.writeHead(200, {'Content-Type': 'application/javascript'})
      res.end(rewriteImport(render))
    }

url.endsWith('.css')判断为一个css文件,我们需要处理css文件的请求,并将css文件的转化成为一个JavaScript文件,该文件会帮助我们再客户端动态生成一份style.

为开发提供极速响应的vite工作原理是怎样的呢?前言 webpack的构建原理 webpack先通过分析JavaScri

然后我们运行一下该项目看看是否和vite一样发送接口请求获取资源文件

为开发提供极速响应的vite工作原理是怎样的呢?前言 webpack的构建原理 webpack先通过分析JavaScri 该项目的主要功能的完整代码:

const http = require('http')
const fs = require('fs')
const path = require('path')
const compilerSfc = require('@vue/compiler-sfc')
const compilerDom = require('@vue/compiler-dom')

function rewriteImport(content) { 
  return content.replace(
    if (s1[0] !== '.' && s1[1] !== '/') {
      return ` from '/@modules/${s1}'`
    } else {
      return s0
    }
  })
}
const server = http.createServer((req, res) => {
  const { url } = req
  const query = new URL(req.url, `http://${req.headers.host}`).searchParams;
  if (url === '/') {
    res.writeHead(200, {
      'content-type': 'text/html'
    })
    let content = fs.readFileSync('./index.html', 'utf-8')
    res.end(content)

  } else if (url.endsWith('.js')) {  // '/src/main.js'
    const p = path.resolve(__dirname, url.slice(1))
    res.writeHead(200, {
      'content-type': 'application/javascript'
    })
    let content = fs.readFileSync(p, 'utf-8')
    res.end(rewriteImport(content))
    
  } else if (url.startsWith('/@modules/')) {  // '/@modules/vue'
    const prefix = path.resolve(__dirname, 'node_modules', url.replace('/@modules/', ''))
    const module = require(prefix + '/package.json').module
    const p = path.resolve(prefix, module)
    const content = fs.readFileSync(p, 'utf-8')
    res.writeHead(200, {
      'content-type': 'application/javascript'
    })
    res.end(rewriteImport(content))
  } else if (url.indexOf('.vue') !== -1) {
    const p = path.resolve(__dirname, url.split('?')[0].slice(1))
    const { descriptor } = compilerSfc.parse(fs.readFileSync(p, 'utf8'))
    if (!query.get('type')) {
      res.writeHead(200, {'Content-Type': 'application/javascript'})
      const content = `
        ${rewriteImport(descriptor.script.content.replace('export default', 'const __script = '))} 
        import { render as __render } from "${url}?type=template" 
        __script.render = __render 
        export default __script
      `
      res.end(content)
    } else if (query.get('type') === 'template') {
      const template = descriptor.template
      const render = compilerDom.compile(template.content, {mode: 'module'}).code
      res.writeHead(200, {'Content-Type': 'application/javascript'})
      res.end(rewriteImport(render))
    }
  } else if (url.endsWith('.css')) {
    const p = path.resolve(__dirname, url.slice(1))
    const file = fs.readFileSync(p, 'utf8')
    const content = `
      const css = "${file.replace(/\n/g,'')}"
      let link = document.createElement('style')
      link.setAttribute('type','text/css')
      document.head.appendChild(link)
      link.innerHTML = css
      export default css
    `
    res.writeHead(200, {'Content-Type': 'application/javascript'})
    res.end(content)
  }
})
server.listen(5173, () => {
  console.log('项目运行在 5173');
})

本文到此就结束了,希望对大家有所帮助,如有不足,恳请各位大侠指点一二,让我功力精进一二!!!

转载自:https://juejin.cn/post/7418797990304858175
评论
请登录