.vue 文件是如何编译成浏览器可执行的文件

vue2官网 其中"安装"介绍了关于Vue的各种版本。

  • 编译器:用来将模板字符串编译成为 JavaScript 渲染函数的代码。
javascript 复制代码
<div id="app">
    <div>{{ a }}</div> 
</div> 
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script> <script> 
const vm = new Vue({ el: '#app', data: { a: 'hello world', }, }) 
</script>

以上是一段简单的Vue2代码, 打开浏览器可以正确显示出 "hello world",- 可以发现 <div>{{ a }}</div> 不是浏览器支持的语法. 所以实际上能显示 hello world, 并不是由以上模板代码直接在浏览器执行的结果, 而是通过"编译器"编译, 再由浏览器执行

  • 接下来用代码为大家演示Vue2是如何将上面代码编译的
  • 首先必须引入"完整版",
  • 打开页面, 在控制台可以发现方法: Vue.compile
  • 将刚才的 template 代码放到编译方法里执行, 结果如下
  • 可以看到 template 被编译成 JavaScript,_c,_v,_s,是vue实例vm上一些方法的简称
  • 编译结果可以翻译成
javascript 复制代码
<script>
    const vm = new Vue({
      el: '#app',
      name: 'App',
      data: () => ({
        a: 'hello world!!!',
      }),
      render() {
        const {_c, _v, _s, a} = this
        //return createElement('div', [createTextNode(toString(a))])
        return  _c('div',[_v(_s(a))])
      }
  })
  </script>

这样 模板template就被编译为了 render函数

  • 以上便是在 .html 文件中使用template 开发, 由 Vue2完整版 进行编译的过程

.vue文件是如何进行编译的?

通常项目中是使用Webpack打包, 再由浏览器引入这些js, css等文件, 那么Webpack是如何对.vue文件进行编译的?

1. ,vue文件

.vue文件.vue 文件是一个自定义的文件类型,用类 HTML 语法描述一个 Vue 组件。每个 .vue 文件包含三种类型的顶级语言块 <template><script><style>,还允许添加可选的自定义块.

2. vue-loader

vue-loader 会解析文件,提取每个语言块,如有必要会通过其它 loader 处理,最后将他们组装成一个 ES Module,它的默认导出是一个 Vue.js 组件选项的对象。

接下来通过vue-loader的源码来了解是如何实现编译的

vue-loader/src/index.ts

vue文件分为 template, script, style 三个部分, 而实际必须通过编译才能在浏览器执行的部分只有template, 所以我们在看 vue-loader 源码时可以重点关注 "template" 关键词

descriptor.template 如上图所示, 在源码搜索 template 关键字可以找到这段处理 script, template, style 的代码, 仔细观察发现这三段都在用 descriptor 对象, 接下来搜索 descriptor, 找到这个变量在哪里生成的 descriptor

再来找 parse 方法

compiler.ts compiler.ts

parse 方法从 vue/compiler-sfc 中引用

至此, 了解到 vue-loader 是通过 @vue/compiler-sfc 的 parse 方法解析 .vue 文件, 从中解析出script, template, style

@vue/compiler-sfc

用一段nodejs代码进行验证

javascript 复制代码
// App.vue
<template>
  <div id="app">
    <div>{{ a }}</div>
    <input type="text" v-model="a">
  </div>
</template>

<script>

export default {
  name: 'App',
  data: () => ({
    a: 'hello world'
  }),
}
</script>
javascript 复制代码
// build.js
const { parse } = require('@vue/compiler-sfc')
const fs = require('fs')

const data = fs.readFileSync('./App.vue')

const { descriptor } = parse(data.toString())

// 结果包含很多项, 本文档中只展示重点字段
console.log(Object.keys(descriptor))

运行 build.js

javascript 复制代码
[
  'styles',
	'template',
  'script',
  // ...
]

通过以上代码可以解析出 .vue 文件的三部分, 接下来开始解析 template vue-template-compiler vue-template-compiler 可以将 template 编译成 Javascript

  • 继续修改 build.js, 根据文档加上 compile 的部分
javascript 复制代码
// build.js
const { parse } = require('@vue/compiler-sfc')
const fs = require('fs')
const compiler = require('vue-template-compiler')

const data = fs.readFileSync('./App.vue')

const { descriptor } = parse(data.toString())
// console.log(Object.keys(descriptor))

console.log(compiler.compile(descriptor.template.content).render)
  • 运行结果如下
javascript 复制代码
with(this){
  return _c(
    'div',
    {attrs:{"id":"app"}},
    [
      _c('div',[_v(_s(a))]),
      _v(" "),
      _c(
        'input',
        {
          directives:[{name:"model",rawName:"v-model",value:(a),expression:"a"}],
          attrs:{"type":"text"},
          domProps:{"value":(a)},
          on:{
            "input": function($event){
              if($event.target.composing) return;
              a=$event.target.value
            }
          }
        }
      )
    ]
  )
}

再将以上代码放到 .html 的 new Vue(...) 方法中进行验证

javascript 复制代码
<div id="app"/>

<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<script>
  const vm = new Vue({
    name: 'App',
    data: () => ({
      a: 'hello world!!!',
    }),
    render() {
      const {_c, _v, _s, a} = this

      return _c(
        'div',
        {attrs: {'id': 'app'}},
        [
          _c('div', [_v(_s(a))]),
          _v(' '),
          _c(
            'input',
            {
              directives: [{name: 'model', rawName: 'v-model', value: (a), expression: 'a'}],
              attrs: {'type': 'text'},
              domProps: {'value': (a)},
              on: {
								// 注意这里的 this, 需要改成箭头函数
                'input': ($event) => {
                  if ($event.target.composing) return
                  this.a = $event.target.value
                },
              },
            },
          ),
        ],
      )
    },
  }).$mount('#app')
</script>

以上便是 Webpack 如何将 .vue 文件编译成浏览器可执行文件的过程

相关推荐
崔庆才丨静觅3 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60613 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了3 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅3 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅4 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅4 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment4 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅5 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊5 小时前
jwt介绍
前端
爱敲代码的小鱼5 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax