vue-loader处理vue文件
loader:"vue-loader" ,引导vue文件被vue-loader/lib/index.js处理
第一步:解析vue文件
const utils = require('@vue/component-compiler-utils')
utils.parse(.vue文件),返回一个json:
{
"template": {
"type": "template",
"content": "\n<div @click=\"setName\">\n app\n</div>\n",
"start": 10,
"attrs": {},
"end": 61
},
"script": {
"type": "script",
"content": "//\n//\n//\n//\n//\n//\n\nexport default {\n name: \"app\",\n methods:{\n setName(){\n console.log('my name');\n }\n }\n}\n",
"start": 82,
"attrs": {},
"end": 236
},
"styles": [
{
"type": "style",
"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\ndiv{\n width: 300px;\n}\n",
"start": 261,
"attrs": {
"scoped": true
},
"scoped": true,
"end": 299
}
],
"customBlocks": [],
"errors": []
}
第二步:生成代码
在vue-loader/lib/index.js中有这样的一个代码:
let code = `
${templateImport}
${scriptImport}
${stylesCode}
/* */
/* normalize component */
/* normalizer 函数式在chrome中执行,并不是在node中执行*/
import normalizer from ${stringifyRequest(`!${componentNormalizerPath}`)}
var component = normalizer(
script,
render,
staticRenderFns,
${hasFunctional ? `true` : `false`},
${/injectStyles/.test(stylesCode) ? `injectStyles` : `null`},
${hasScoped ? JSON.stringify(id) : `null`},
${isServer ? JSON.stringify(hash(request)) : `null`}
${isShadow ? `,true` : ``}
)
`.trim() + `\n`
code += `\nexport default component.exports`
这个模板字符串最终形式如下:
这是一个模块 有import 和export ,和我们自己写的代码一样。
import { render, staticRenderFns } from "./app.vue?vue&type=template&id=6940f262&scoped=true&"
import script from "./app.vue?vue&type=script&lang=js&"
export * from "./app.vue?vue&type=script&lang=js&"
import style0 from "./app.vue?vue&type=style&index=0&id=6940f262&scoped=true&lang=css&"
import normalizer from "!../../../../node_modules/vue-loader/lib/runtime/componentNormalizer.js"
var component = normalizer(
script,
render,
staticRenderFns,
false,
null,
"6940f262",
null
)
export default component.exports
这样的代码被webpack接收之后发现有import语句,重新调用vue-loader第二次对同一个vue文件的处理。
不过这次query上有了type类型,一进到vue-loader就被截胡了,直接根据type参数跳转到另外的loader处理。跳转代码如下:
if (incomingQuery.type) {
return selectBlock(
descriptor,
loaderContext,
incomingQuery,
!!options.appendExtension
)
}
另外loader是从哪里来的呢,这就要说到new VueLoaderPlugin()的用意了。
VueLoaderPlugin的用处是利用webpack钩子在旧rules上添加了其他loader。
如果type=script,最终的loader如下:
-!../../../node_modules/cache-loader/dist/cjs.js??ref--12-0
!../../../node_modules/babel-loader/lib/index.js
!../../../node_modules/cache-loader/dist/cjs.js??ref--0-0
!../../../node_modules/vue-loader/lib/index.js??vue-loader-options
!./topnav.vue?vue&type=script&lang=js&"
如果type=template,最终的loader如下:
-!cache-loader?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"57422ecc-vue-loader-template"}
!../../../node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options
!../../../node_modules/cache-loader/dist/cjs.js??ref--0-0
!../../../node_modules/vue-loader/lib/index.js??vue-loader-options
!./history.vue?vue&type=template&id=f89b51d2&scoped=true&"
如果type=style,最终的loader如下:
-!../../../../node_modules/vue-style-loader/index.js??ref--6-oneOf-1-0
!../../../../node_modules/css-loader/index.js??ref--6-oneOf-1-1
!../../../../node_modules/vue-loader/lib/loaders/stylePostLoader.js
!../../../../node_modules/postcss-loader/src/index.js??ref--6-oneOf-1-2
!../../../../node_modules/cache-loader/dist/cjs.js??ref--0-0
!../../../../node_modules/vue-loader/lib/index.js??vue-loader-options
!./voice.vue?vue&type=style&index=0&id=b09c9dcc&scoped=true&lang=css&"
1.加⼊!前缀, 不使⽤config loader中的normal loader,例如require('!a-loader!./a.j s');
2.加⼊!!前缀,不使⽤config loader中的pre loader,normal loader,post loader,例如 require('!!a-loader!./a.js');
3.加⼊-!前缀,不使⽤config loader中的normal loader,pre loader,例如require('-!a -loader!./a.js');
上面的loader处理之后分别会生成如下的代码:
utils.compileTemplate处理template,返回值被 normalizer的 render, staticRenderFns接收
{
ast: {
type: 1,
tag: 'div',
attrsList: [ [Object] ],
attrsMap: { '@click': 'setName', class: 'sdsd' },
rawAttrsMap: {},
parent: undefined,
children: [ [Object], [Object] ],
plain: false,
staticClass: '"sdsd"',
hasBindings: true,
events: { click: [Object] },
static: false,
staticRoot: false
},
code: 'var render = function() {\n' +
' var _vm = this\n' +
' var _h = _vm.$createElement\n' +
' var _c = _vm._self._c || _h\n' +
' return _c("div", { staticClass: "sdsd", on: { click: _vm.setName } }, [\n' +
' _vm._v("\\n app\\n "),\n' +
' _c("img", { attrs: { src: "./a.png", alt: "" } })\n' +
' ])\n' +
'}\n' +
'var staticRenderFns = []\n' +
'render._withStripped = true\n',
source: '\n' +
'<div @click="setName" class="sdsd">\n' +
' app\n' +
' <img src="./a.png" alt="">\n' +
'</div>\n',
tips: [],
errors: []
}
const { code } = compiled
return code + `\nexport { render, staticRenderFns }`
utils.compiledStyle处理的结果如下, 返回值被 normalizer的 style0接收
const { code, map, errors } = {
code: '\ndiv[data-v-12]{\n width: 300px;\n}\np[data-v-12]{\n background: red;\n}\n',
map: undefined,
errors: [],
rawResult: LazyResult {
stringified: true,
processed: true,
result: Result {
processor: [Processor],
messages: [],
root: [Root],
opts: [Object],
css: '\n' +
'div[data-v-12]{\n' +
' width: 300px;\n' +
'}\n' +
'p[data-v-12]{\n' +
' background: red;\n' +
'}\n',
map: undefined,
lastPlugin: [Function]
}
}
}
this.callback(null, code, map)
脚本部分没有添加额外的处理,直接返回了vue文件中的script部分,返回值被 normalizer的 script接收
最后回到normalizer,这个在浏览器执行的方法会接收到如下参数:
script: 就是在vue组件中export default中定义的所有内容
render: 由template生成的render函数,在上面能看到
staticRenderFns :由template生成,上面能看到
false:代表不是函数组件
null: 代表是否在页面插入组件行内样式,此处没有使用sytle-loader处理,结果为null
6940f262 : 组件中样式的scopeId
如此一个组件就编译完了。
中间的一些状态可以执行这个文件地址
vue-loader处理vue文件的更多相关文章
- Vue Loader
介绍 允许为 Vue 组件的每个部分使用其它的 webpack loader,例如在 <style> 的部分使用 Sass 和在 <template> 的部分使用 Pug(模板 ...
- vue 快速入门 系列 —— vue loader 上
其他章节请看: vue 快速入门 系列 vue loader 上 通过前面"webpack 系列"的学习,我们知道如何用 webpack 实现一个不成熟的脚手架,比如提供开发环境和 ...
- vue中的单文件组件
之前都是在html文件中写组件的css,组件的js,组件的模板来演示vue组件的语法,下面介绍以.vue结尾的单文件组件.vue-loader是一个Webpack的loader,可以将单文件组件转换为 ...
- webpack4对第三方库css,项目全局css和vue内联css文件提取到单独的文件(二十二)
在讲解提取css之前,我们先看下项目的架构如下结构: ### 目录结构如下: demo1 # 工程名 | |--- dist # 打包后生成的目录文件 | |--- node_modules # 所有 ...
- vue入门之单文件组件
介绍 在很多 Vue 项目中,我们使用 Vue.component 来定义全局组件,紧接着用 new Vue({ el: '#container '}) 在每个页面内指定一个容器元素. 这种方式在很多 ...
- vue 目录结构与文件配置说明
目录结构与文件配置说明 首先对目录结构进行说明, 1.build目录,主要利用webpack与node插件启动一些相关服务的js文件 2.config目录主要是针对开发环境,生产环境,测试环境的配置信 ...
- vue项目中一些文件的作用
原文 简书原文:https://www.jianshu.com/p/38749e5bec3c 大纲 1.vue项目结构 2.主要的配置文件 2.1.package.json 2.2.dev-serve ...
- vue 快速入门 系列 —— vue loader 下
其他章节请看: vue 快速入门 系列 vue loader 下 CSS Modules CSS Modules 是一个流行的,用于模块化和组合 CSS 的系统.vue-loader 提供了与 CSS ...
- vue 快速入门 系列 —— vue loader 扩展
其他章节请看: vue 快速入门 系列 vue loader 扩展 在vue loader一文中,我们学会了从零搭建一个简单的,用于单文件组件开发的脚手架.本篇将在此基础上继续引入一些常用的库:vue ...
- vue源码入口文件分析
开发vue项目有段时间了, 之前用angularjs 后来用 reactjs 但是那时候一直没有时间把自己看源码的思考记录下来,现在我不想再浪费这 来之不易的思考, 我要坚持!! 看源码我个人感觉非常 ...
随机推荐
- 通过PHP工具箱-站点域名管理(创建本地虚拟主机)
工具:php程序员工具箱(网上很多请自己搜索下载) 1.点击其它选项菜单 -> 选择站点域名管理.如下图 2.进入站点域名管理.如下图(初始的时候,站点为空) 3.设置站点管理.如下图 网站域名 ...
- Alink漫谈(十三) :在线学习算法FTRL 之 具体实现
Alink漫谈(十三) :在线学习算法FTRL 之 具体实现 目录 Alink漫谈(十三) :在线学习算法FTRL 之 具体实现 0x00 摘要 0x01 回顾 0x02 在线训练 2.1 预置模型 ...
- The option-critic architecture
Abstract 时间抽象是强化学习中扩大学习和规划的关键.虽然计划与时间扩展的行动是众所周知的,但从数据中自主地创建这样的抽象仍然具有挑战性.我们在option框架内解决这个问题[Sutton,Pr ...
- python xpath的基本用法
XPath是一种在XML文档中查找信息的语言,使用路径表达式在XML文档中进行导航.学习XPath需要对XML和HTML有基本的了解. 在XPath中,有七种类型的节点:文档(根)节点.元素.属性.文 ...
- centOS7.*安装nginx和简单使用
安装nginx 去官网下载对应的nginx包,推荐使用稳定版本. 上传下载好的包到服务器 安装依赖环境 安装gcc环境. yum install gcc-c++ 安装PCRE库,用于解析正则表达式. ...
- PHP tempnam() 函数
定义和用法 tempnam() 函数在指定的目录中创建一个具有唯一文件名的临时文件. 该函数返回新的临时文件名,如果失败则返回 FALSE. 语法 tempnam(dir,prefix) 参数 描述 ...
- PHP preg_replace_callback_array() 函数
preg_replace_callback_array 函数执行一个正则表达式搜索并且使用一个回调进行替换.高佣联盟 www.cgewang.com 该函数在 PHP7+ 版本支持. 语法 mixed ...
- 2020牛客暑假多校训练营 第二场 H Happy Triangle set 线段树 分类讨论
LINK:Happy Triangle 这道题很容易. 容易想到 a+b<x a<x<b x<a<b 其中等于的情况在第一个和第三个之中判一下即可. 前面两个容易想到se ...
- 解决痛苦的方法/cy
这篇文章 源于我所有痛苦的回忆. 由于痛苦太多了 体会完了 所以 觉得这些都不算是什么大问题了 所以 这里 是解决痛苦的方法. 真的很痛苦的话 可以这样 对着全班人喊你们 都没我强 因为 你们都没有我 ...
- 3.29省选模拟赛 除法与取模 dp+组合计数
LINK:除法与取模 鬼题.不过50分很好写.考虑不带除法的时候 其实是一个dp的组合计数. 考虑带除法的时候需要状压一下除法操作. 因为除法操作是不受x的大小影响的 所以要状压这个除法操作. 直接采 ...