从vuecli3学习webpack记录(三)基类Tapable和Hook分析

在查看webpack(及插件)源码的过程中,我们会经常看到类似这样的代码 compiler.hooks.done.tap('vue-cli-service serve',() => {}); // 或者 compilation.hooks.buildModule.tap("ProgressPlugin", moduleAdd); 或者 compiler.hooks.environment.call(); 即调用hooks.xxx.tap(还有类似的tapPromise/tapAsync)方法hooks.xxx.call(还有类似的promise/callAsync)方法。首先一般是Compiler和Compilation类的实例里面会调用上市tap和call方法。首先,它们都继承自Tapable类,并在其构造函数里面都有一个hooks的对象,该对象的value都是一个Hook的子类的实例。以Compiler类为例。 class Compiler extends Tapable { constructor(context) { super(); this.hooks = { /** @type {SyncBailHook<Compilation>} */ shouldEmit: new SyncBailHook(["compilation"]), /** @type {AsyncSeriesHook<Stats>} */ done: new AsyncSeriesHook(["stats"]), /** @type {AsyncSeriesHook<>} */ additionalPass: new AsyncSeriesHook([]), /** @type {AsyncSeriesHook<Compiler>} */ beforeRun: new Read more…

从Javascript引擎、编译器和作用域来理解函数声明、普通的变量声明

首先声明本文内容主要来自《You Don’t Know Js: Scope & Closures》中文版《你不知道的Javascript 上卷》,本人对于Javascript引擎、编译器和作用域的理解也主要源于该书与自己在控制台的调试,欢迎和大家一同学习交流。 编译原理 一般分为三个步骤: 1. 分词/词法分析 把代码片段分成对语言有意义的词法单元 2. 解析/语法分析将词法单元转换为AST(抽象词法树) 3. 代码生成将AST转化为可以执行的代码 具体细节可以参看原书。总的来说代码片段会在代码执行前极短的时间进行编译 Javascript引擎 负责Javascript的编译和执行全过程 编译器 Javascript引擎的好朋友,负责解析和代码生成过程 作用域 Javascript的另一个好朋友,负责收集、维护、生成声明的变量,并且它有一套自己的规则,确保当前执行的代码对这些变量的访问权限。 以书上的示例var a = 2为例,这一句声明,在js执行时,对引擎来说是分两部分的,第一部分是在在编译过程中完成,第二部分是在引擎运行时处理。1. 编译器编译过程 var a 编译器会询问作用域是否已经存在一个该名称的变量,如果有就直接忽略当前的声明,如果没有,就要求作用域声明一个变量a; var a;就被忽略了,所以打印出来还是1 var b;就被忽略了,所以打印出来还是函数这就是所谓的“变量提升”吧2. 编译器生成完代码供引擎执行过程 a = 2引擎会先问作用域是否存在变量a,作用域会告知引擎:有的(编译器刚刚已经要求作用域声明了),这时引擎就会直接用到变量a,并将2赋值给a;如果当前作用域没有找到变量a的话,作用域会一直向上查找,知道全部作用域找不到则报错为止。 左查询和右查询 这里的左右是相对于赋值操作而已的,并非是按照=的左右的。通俗的说,我们要进行赋值操作,所有要找到目标,也就是赋值给谁,然后就是取到将要把什么值赋值给该目标,就是要取到赋值的数据来源。需要特别提到的是在函数执行时,参数赋值的过程。比如 function foo(a){     console.log(a); // 2 } foo(2); 代码中隐式的a=2的过程容易被忽略,这个操作发生在2被当作参数传递给foo(…)函数式,2会被分配给参数a,这是就存在一个左查询。 函数声明、普通的变量声明+赋值的区别 // 代码a function foo(a) { } Read more…

用div+css模拟类excel表格对角线(斜线)

我们先看html代码吧 <table> <caption>用div+css模拟类excel表格对角线(斜线)</caption> <tr> <th style="width:80px;"> <div class="out"> <b>科目</b> <em>姓名</em> </div> </th> <th>数学</th> <th>语文</th> </tr> <tr> <td>张三</td> <td>92</td> <td>62</td> </tr> <tr> <td>李四</td> <td>91</td> <td>67</td> </tr> </table> 第一种写法 css如下 * {   padding: 0;   margin: 0; } table {   border-collapse: collapse;   border: 1px #525152 solid;   width: 50%; Read more…

用webpack的require.context优化vue store和router文件

早期右边博文专门讲了下require.context的用法和简单用法介绍《用webpack的require.context() 简化你的代码》 这次说点自己在vue项目中的具体应用吧 store 首先看我的store的目录结构: 这里的每个文件夹都是一个module,所以在store/index.js里面可以这样写 import Vue from 'vue'; import Vuex from 'vuex'; import Axios from './axios'; import Api from './api'; const modules = {}; // 只匹配子文件夹的index.js ./brand/index.js const files = require.context("./", true, /^\.\/(\w*\/)+index\.js$/); files.keys().forEach(file => { const moduleName = file.replace(/(^\.\/)|(\/index\.js$)/g, ""); modules[moduleName] = files(file).default || files(file); }); Vue.use(Vuex); Read more…

vue里面使用debounce,throttle注意点

我们有时在自己的vue项目中不可避免的要监听类似scroll事件的,这是如果相对性能影响少点,只能会想到debounce防抖之类的。但是我们要注意了,addEventListener和removeEventListener必须要是同一个函数才行哦,不然removeEventListener是无法移除事件的,这样就容易造成内存泄露了。 平时我们的debounce一般这么用 methods: { createDebounce(ms, fn) { let prevTime; return () => { if (prevTime) { if (Date.now() – prevTime >= ms) { fn(); prevTime = null; } } else { prevTime = Date.now(); } }; }, scrollFn() { // …处理逻辑 } } 那我们怎么配合addEventListener和removeEventListener使用呢? 比如 mounted() { window.document.addEventListener('scroll', this.createDebounce(800, this.scrollFn); Read more…

element-ui表单源码解析之el-input

关于表单校验el-input做的主要工作就是跟el-form-item交互,把input的相关事件发送给el-form-item,上一篇已经讲到在el-form-item的mounted的生命周期里面有如下代码的 this.$on('el.form.blur', this.onFieldBlur); this.$on('el.form.change', this.onFieldChange); 我们在el-input里面依然可以看到inject,鉴于有很多单独使用el-input的地方,所以也给了默认值。 inject: { elForm: { default: '' }, elFormItem: { default: '' } }, 看看computed 其实这里面的比较简单,基本都是控制状态和样式的,有些状态是由el-form或者el-form-item控制的。 watch 直接监听父级传入的value,根据value来设置组件内保存的currentValue。 看看 methods focus() { (this.$refs.input || this.$refs.textarea).focus(); }, blur() { (this.$refs.input || this.$refs.textarea).blur(); }, select() { (this.$refs.input || this.$refs.textarea).select(); }, handleFocus(event) { this.focused = true; this.$emit('focus', event); Read more…

element-ui表单源码解析之el-form-item

上一篇看了el-form,功能比较简单,现在来看看el-form-item <!–el-form-item源码–> <template> <div class="el-form-item" :class="[{ 'el-form-item–feedback': elForm && elForm.statusIcon, 'is-error': validateState === 'error', 'is-validating': validateState === 'validating', 'is-success': validateState === 'success', 'is-required': isRequired || required, 'is-no-asterisk': elForm && elForm.hideRequiredAsterisk }, sizeClass ? 'el-form-item–' + sizeClass : '' ]"> <label :for="labelFor" class="el-form-item__label" :style="labelStyle" v-if="label || $slots.label"> <slot name="label">{{label + form.labelSuffix}}</slot> Read more…

element-ui表单源码解析之el-form

表单时大家常用的,根据本站的百度统计后台显示来到道招网的程序很多都在关注《element-ui动态表单async-validate校验 please transfer a valid prop path to form item!》 看来很多网友对element-ui的校验(或者说是async-validator)使用不太熟悉,想了想还是有必要分享下element-ui的表单校验机制的。 首先表单校验分el-form, el-form-item以及里面的el-input, el-select等。 这里就以el-form, el-form-item和el-input组合为例。为了讲的更加详细,决定分一个系列来讲。毕竟码字多了就想草草结束。。。 先直接看el-form吧,这里的代码很少,毕竟主要内容是以slot插入的。 <template> <form class="el-form" :class="[ labelPosition ? 'el-form–label-' + labelPosition : '', { 'el-form–inline': inline } ]"> <slot></slot> </form> </template> 属性就不多说了,跟校验相关的就是model和rules。还有就是validateOnRuleChange,它默认是true,并且有这样的watch存在 watch: { rules() { if (this.validateOnRuleChange) { this.validate(() => {}); } } }, Read more…

Vue2.6.10源码分析(一)vue项目怎么神奇的跑起来的

先看index.html的代码吧 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>mini Vue</title> </head> <body> <div id='app'> </div> </body> <script src='./utils.js'></script> <script src='./index.js'></script> <script> var vm = new Vue({ name: 'root', el: '#app', render(h) { return h('div', 'ok'); }, }); console.log('vm ', vm); </script> </html> 基本就是vue的index.html加上main.js的结合体,这里为了避免index.js太长,把一些基础方法放到了utils.js里面 Read more…

准备做点开源前端练手小项目

今天将自己自己最近写的练手代码整理放到了github上,主要是 一个是后端,github地址:https://github.com/shadowprompt/daozhao_graphql 一个前端,github地址: https://github.com/shadowprompt/daozhao_vue_ssr 后端项目有以下功能: 支持wordpress博客(道招网)数据(文章、分类、标签)的GraphQL查询,接口地址 https://www.daozhao.com.cn/graphql PWA的订阅、查询、推送功能 地址https://www.daozhao.com.cn 接口层面支持小程序的access_token获取及定时获取,获取消息模板推送消息,JWT登录,encryptedData解码unionId等 前端项目有以下功能:预览地址:http://blog.daozhao.com.cn 调用GraphQL接口实现wordpress的SPA化,扁平化主题(模仿hexo-theme-indigo主题,http://hexo.daozhao.com.cn(已废弃) 支持typescript 后期计划: 完善wordpress的扁平化主题,完善后使用域名https://www.daozhao.com.cn访问 支持服务端渲染SSR 完善小程序功能前端页面 结合github(或者部署gitlab)和jenkins支持一键发版 2020年4月23日,更新了项目最新地址,并且之前的vue预览版已经转成正式版,道招网正式启用vue版前端