前端工程化

136 阅读4分钟

什么是前端工程化

所谓的前端工程化就是通过技术选型,代码规范,代码测试,部署,监控,性能优化提高开发效率和质量的一种理念。

image.png

前端工程化工具(webpack)

webpack基础 webpack构建工具在日常的使用中主要使用5个属性配置,分别是入口(evtry),出口(ouput) loader 插件(plugin) 模式(mode) 1.入口(entry)

module.export={
entry:"./index.js"
}

2.出口(output)

module.export={
output:{
path:path.resolve(__dirname,'dist') //打包输出目录
filename:"build.js" //打包输出的文件
}
}

3.loader

loader只专注于转换文件完成压缩打包的任务,仅仅是为了打包,我们常见的loader,css-loader,url-loader ,file-loader vue-loaer style-loader babel-loader 等

module.export={
  module:{
  rules:[{
     test:/\.txt$/,use:"raw.loader"
  }]
  }
}

在我们使用自定义loader的时候对于loader进行统一的管理 我们可以通过配置的方式去实现

module.export={
//统一配置loader
resolveLoader:{
modules:['node_modules',path.resolve(__dirname,'loaders')] //loaders文件夹下面的文件名则是loader的名称,使用的时候就可以直接使用名称去加载对应的loade了
}
}

4.plugin

plugin也是为了扩展webpack的功能,但是 plugin 是作用于webpack本身上的。而且plugin不仅只局限在打包,资源的加载上,它的功能要更加丰富。从打包优化和压缩,到重新定义环境变量,功能强大到可以用来处理各种各样的任务。webpack提供了很多开箱即用的插件:CommonChunkPlugin主要用于提取第三方库和公共模块,避免首屏加载的bundle文件,或者按需加载的bundle文件体积过大,导致加载时间过长,是一把优化的利器。而在多页面应用中,更是能够为每个页面间的应用程序共享代码创建bundle。
module.exports = {
 //...
 plugins: [
   new webpack.DefinePlugin({
     // Definitions...
   }),
 ],
};

常见的plugin有 HtmlWebpackPlugin:生成html模板的,CopyWebpackPlugin 静态资源移动的 HotModuleReplacementPlugin 热更新 OptimizeCSSPlugin 压缩css webpack.DefinePlugin编译时候定义常量等

vuecli中的webpack的配置

//vue.config.js
module.export={
outputDir:"dist"//输出路径
assetsDir:"/"静态资源生成目录
publicPath:"/"打包后的目录
configureWebpack:{ //简单webpack的配置会通过webpack-merge进行合并(直接修改webpack的配置)
  plugins:[
  new HtmlWebpackPlugin()
  ]
  
},
chainWebpack:config=>{//对于webpack更细粒度的修改(高级 采用链式调用的方式)
 config.modlue.rule('vue').use('vue-loader')
 //修改已有的loader
config.module
      .rule('vue')
      .use('vue-loader')
        .tap(options => {
          // 修改它的选项...
          return options
        })
 //添加loader

 config.module
      .rule('graphql')
      .test(/.graphql$/)
      .use('graphql-tag/loader')
        .loader('graphql-tag/loader')
        .end() //结束上一个loader  end()返回的是上一级 结束当前的use对象 使用下一个   loader
      // 你还可以再添加一个 loader
      .use('other-loader')
        .loader('other-loader')
        .end()
   //添加plugin
 .plugin('html-template')
    .use(HtmlWebpackTemplate)
    .end()
  .plugin('script-ext')
    .use(ScriptExtWebpackPlugin)
    .before('html-template');
   }
}

自定义loader和plugin

自定义loader
//同步loader
const {getOptions}=require('locader-utils') //用于获取传入loader的option


module.exports=function(context,map,mata){
//context是传入到loader要处理的数据 并且每个loader都要将传入的数据进行返回 或者调用loader内部的callbacK函数将数据返回
const options=getOptions(this)//获取loader的options参数
return context    或者 //this.callback(null,context)
}
//异步执行
module.exports=function(context,map,meta){
const callback=this.async()
//对于context进行的一系列操作
 setTimeout(()=>{
 callback(null,context)//异步处理
 },3000)


}
//因为定义的loaderzaiwebpack中执行的顺序并不是按照定义loader中来的,如果想按照定义的loader是做一些操作的时候可以使用pitch函数
module.exports.pitch=function(context){ //参数是处理的内容
 //执行操作
}

自定义plugin
class CopyrightWebpackPlugin{
   constructor(options){
   }
   apply(complier){
       //同步插件
   complier.hooks.emit.tap('plugin名称',compations=>{

   })

        //tap表示的是同步执行插件,没有手动执行cb(),tapAsync()异步执行插件 参数有两个:1.自定义plugin的名称2.回调函数,需要执行cb tapPromise参数1.webpack本次打包的实例对象 需要将promose实例返回
        // tapPromise()异步延迟执行  中的第一个参数则是webpackpack的实例
   
       // 异步方式
       compiler.hooks.emit.tapAsync('CopyrightWebpackPlugin',(compiation,cb)=>{
           //compication 本次打包的构建实例 
           compiation.assets['index.text']={
               source(){
                   return '我是资源'
               },
               size(){
                 return 21
               }
           }
           cb()

       })

       compiler.hooks.afterPlugins.tap('CopyrightWebpackPlugin',(compiation)=>{
           //compiation则是本次构建中的资源信息
           console.log('插件以初始化完成')
          
       })
       //异步延迟
       compiler.hooks.run.tapPromise('CopyrightWebpackPlugin', compiler => {
       
         //compoler 则是webpack的实例
           return new Promise(resolve => setTimeout(resolve, 1000)).then(() => {
             console.log('以具有延迟的异步方式触及 run 钩子')
           })
         })
   
   
   //对于我们在日常的开发中如何选择hook钩子所进行性那种操作(同步操作,异步操作,promise操作)取决于钩子的类型,当钩子带有asyncseries的时候则代表的是异步钩子(可以执行tap,tapAsync,tapPromise) 如果是sync则是同步钩子只能是tap ,如果是AsyncParallel则代表的是并行异步钩子 (可以执行tap,tapAsync,tapPromise)进行并行执行
   }
}
//使用
config.plugin('copys').use(CopyrightWebpackPlugin,[{name:"esetset"}]) //数组中存在多个对象的时候只取第一个对象

js函数式编程

所谓的函数式编程就是一种抽象的运算过程,函数式的函数并非对于过程运算,而是函数的映射,并且该函数 会根据传入的相同的参数永远数据的值相同。

  1. 函数式编程的函数都是纯函数(相同的输入相同的输出)

    //非纯函数
    
    let min=18
    let limit=age=>age>min
    //这个函数如果输入相同的age 但是外部改变了min 则会得到不同的结果
    缺点:过分依赖于外部变量或者外部模块,导致系统的复杂性提高
    
    //纯函数
    
    let limit=(age,min)=>age>min
    //则如果age 和min相同的话   这个函数的输出值永远相同
    
    
  2. 高阶函数(函数作为参数传递给另一个函数,函数最为返回值被另一个函数返回)

function outfun(arg){
let a=18

return function(){
     return  arg+a
}
}
//也就是所谓的闭包
  1. 函数柯里化(传递给函数的一部分参数用于函数自身的功能调用,让该函数返回一个函数去处理其他的参数)
function add(x,y){
return x+y
}
//柯里化后
function add(x){
retrun function(y){
    retrun x+y
}
}

  1. 组合函数(通过优雅的方式去实现纯函数的解耦) 组合函数可以理解是 定义一种函数参数都是函数 在这种函数中去执行传入的函数的方式
let compose=function(f,g){
return function(x){
  retrun f(g(x))  //将g函数执行的结果传递给f函数
}

}
eg:
let add=x=>x+1
let mul=y=>y*5
compose(add,mul)(2) ///11
这种方式的有点就是每个函数都是单独的不会依赖环境中的变量  每个函数都可以单独的在不同环境下去使用