前端工程化知识零散学习

212 阅读4分钟

require.context()

require.context()是一个webpack的api,主要作用是批量导入指定模块,解决了手动导入模块的繁琐。

用法: 通过执行require.context()函数获取一个特定的上下文(特定文件夹)。然后获取当前的文件,实现导入。

语法:require.context(String:directory,Boolean:useSubdirectories,regExp:regexp)

参数: directory:String,读取文件的路径 useSubdirectories:Boolean,是否遍历文件子目录。 regexp:Regexp,匹配文件的正则表达

分析: 什么时候需要使用require.context() 如果有以下情况,可以使用。 盗图: 当导入模块时:

index.js

模块文件:

module.js

基于Vue-cli的一个自定义UI插件的小demo 文件结构:

文件结构

我的packages文件夹中有两个组件ButtonIcon,我需要将他们导入到index.js文件中然后注册给一个暴露了install方法的对象,之后就可以在 main.js中使用Vue.use()方法注册插件全局使用。 使用vue-cli3自定义插件并发布到npm参考我的文章:vue-cli3自定义插件并发布到npm

如果不使用require.context()方法时,是这样做的。 index.js

import Button from './Button.vue'; //导入Button组件
import Icon from './Icon.vue';//导入Icon组件
let MsComponent = {};
MsComponent.install = function(Vue,options){
    Vue.component('ms-button',Button); //全局注册Button组件
    Vue.component('ms-icon',Icon); //全局注册Icon组件
}

export default MsComponent

可以看到手动import每个需要的组件,然后分别调用Vue.component()去进行全局注册。 这样如果我的组件很多的情况下,逐个导入与注册就会让代码变得非常长。一点都不优雅。

使用require,context()

let MsComponent = {};
MsComponent.install = function(Vue,options){
    let components = require.context('./',true,/\.vue$/);//当前文件夹下以.vue结尾的所有文件
    console.log(components); // components
    components.keys().forEach((item)=>{
        let componentConfig = components(item)
        console.log(componentConfig) //componentConfig
        Vue.component(componentConfig.default.name,componentConfig.default)
    })

}
export default MsComponent
  1. 注释里面的输出 components 是一个方法

    components是一个方法

  2. 注释里面的输出 components.keys() 方法返回的是所有的组件路径list.

    所有的组件list

  3. 注释里面的输出 componentConfig 是一个对象里面包含了组件的信息。

    componentConfig组件的信息

比如default属性里面包含了组件的生命周期,name,render方法等。

源码 大概长这个样子:

var map = {
	"./Button.vue": "./src/packages/Button.vue",
	"./Icon.vue": "./src/packages/Icon.vue"
};


function webpackContext(req) {
	var id = webpackContextResolve(req);
	return __webpack_require__(id);
}
function webpackContextResolve(req) {
	if(!__webpack_require__.o(map, req)) {
		var e = new Error("Cannot find module '" + req + "'");
		e.code = 'MODULE_NOT_FOUND';
		throw e;
	}
	return map[req];
}
webpackContext.keys = function webpackContextKeys() {
	return Object.keys(map);
};
webpackContext.resolve = webpackContextResolve;
module.exports = webpackContext;
webpackContext.id = "./src/packages sync recursive \\.vue$";

参考文章:使用require.context实现前端工程自动化

babel工作原理

Babel本质就是操作AST来完成代码转译; 三个阶段:

  1. Parse(解析):将源代码转换成更加抽象的表示方法(AST抽象语法树)
  2. Transform(转换):对AST(抽象语法树)做一些特殊处理,使其更符合编译器的期望
  3. Generate(代码生成):将第二步经过转换的AST(抽象语法树)生成新的代码

参考: AST抽象语法树 初学 Babel 工作原理

网络请求Axios

Axios是一个支持node端和浏览器端,支持Promise,拥有丰富的配置项的网络请求工具。

安装:npm install axios

执行GET请求

axios.get("/user?ID=123")
  .then((response)=>{
     //捕获请求成功
  })
  .catch((error)=>{
    //捕获请求失败
  })

GET请求参数可以直接拼接在路径后面,也可以直接在第二个参数中传入一个对象,将参数放置在对象的params属性上

axios.get("/user",{
  params:{
    ID:123
  }
})
.then((response)=>{
   //捕获请求成功
})
.catch((error)=>{
  //捕获请求失败
})

执行POST请求

axios.post("/user",{
  name:"mstian",
  age:18
})
.then((response)=>{
  //捕获请求成功
})
.catch((error)=>{
  //捕获请求失败
})

POST请求参数为第二个参数是一个对象。

执行多个并发请求:

function getUserAccount(){
  return axios.get("/user")
}

function getUserPermission(){
  return axios.get("/user/permission")
}

axios.all([getUserAccount(),getUserPermission()])
.then(axios.spread((acct,perms)=>{
   //两个请求都成功
}))

Axios API 可以通过向axios传递相关配置来创建请求

axios({
  method:"post",
  url:"/user',
  data:{
    name:"mstian",
    age:18
  }
});

axios默认为get请求

axios("/user")
//默认发送get请求

为了方便所有请求方法都有别名

axios.request(config)
axios.get(url[,config])
axios.post(url[,config])
axios.put(url[,config])

创建实例 可以使用自定义配置新建一个axios实例 axios.create([config]);

var instance = axios.create({
  baseURL:"http://www.tianleilei.cn",
  timeout:1000
})

请求拦截

instance.interceptors.request.use((config)=>{
  //config请求体
  //可以在这里做一些请求前的配置,比如动态增加header
  config.headers.Authorization = "token"
  return config
},(err)=>{
   return Promise.reject(err)
})

响应拦截

instance.interceptors.response.use((response)=>{
  //对响应数据加工处理
  if(response.status>=200 && response.status<300 || response.status === 304){
    return Promise.resolve(response.data)
  }else{
    return Promise.reject(response)
  }
},(error)=>{
  console.log(error)
})

响应结构

{
  // `data` 由服务器提供的响应
  data: {},

  // `status` 来自服务器响应的 HTTP 状态码
  status: 200,

  // `statusText` 来自服务器响应的 HTTP 状态信息
  statusText: 'OK',

  // `headers` 服务器响应的头
  headers: {},

  // `config` 是为请求提供的配置信息
  config: {}
}

全局axios默认值

axios.defaults.baseURL = "https://www.api.example.com"
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

网络请求封装参考

import axios from 'axios'
import Qs from 'qs'
import store from '@/store'
import router from '@/router'
import Vue from 'vue'
import { Loading, Message } from 'element-ui' // 引用element-ui的加载和消息提示组件

const $axios = axios.create({
  // 设置超时时间
  timeout: 30000,
  // 基础url,会在请求url中自动添加前置链接
  baseURL: process.env.VUE_APP_BASE_API
})
Vue.prototype.$http = axios // 并发请求
// 在全局请求和响应拦截器中添加请求状态
let loading = null

// 请求拦截器
$axios.interceptors.request.use(
  config => {
    loading = Loading.service({ text: '拼命加载中' })
    const token = store.getters.token
    if (token) {
      config.headers.Authorization = token // 请求头部添加token
    }
    return config
  },
  error => {
    return Promise.reject(error)
  }
)
// 响应拦截器
$axios.interceptors.response.use(
  response => {
    if (loading) {
      loading.close()
    }
    const code = response.status
    if ((code >= 200 && code < 300) || code === 304) {
      return Promise.resolve(response.data)
    } else {
      return Promise.reject(response)
    }
  },
  error => {
    if (loading) {
      loading.close()
    }
    console.log(error)
    if (error.response) {
      switch (error.response.status) {
        case 401:
          // 返回401 清除token信息并跳转到登陆页面
          store.commit('DEL_TOKEN')
          router.replace({
            path: '/login',
            query: {
              redirect: router.currentRoute.fullPath
            }
          })
          break
        case 404:
          Message.error('网络请求不存在')
          break
        default:
          Message.error(error.response.data.message)
      }
    } else {
      // 请求超时或者网络有问题
      if (error.message.includes('timeout')) {
        Message.error('请求超时!请检查网络是否正常')
      } else {
        Message.error('请求失败,请检查网络是否已连接')
      }
    }
    return Promise.reject(error)
  }
)

// get,post请求方法
export default {
  post(url, data) {
    return $axios({
      method: 'post',
      url,
      data: Qs.stringify(data),
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
      }
    })
  },
  get(url, params) {
    return $axios({
      method: 'get',
      url,
      params
    })
  }
}

参考: www.kancloud.cn/yunye/axios…

未完待续。。。

写在最后:文中内容大多为自己平时从各种途径学习总结,文中参考文章大多收录在我的个人博客里,欢迎阅览www.tianleilei.cn