什么是前端工程化
所谓的前端工程化就是通过技术选型,代码规范,代码测试,部署,监控,性能优化提高开发效率和质量的一种理念。
前端工程化工具(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函数式编程
所谓的函数式编程就是一种抽象的运算过程,函数式的函数并非对于过程运算,而是函数的映射,并且该函数 会根据传入的相同的参数永远数据的值相同。
-
函数式编程的函数都是纯函数(相同的输入相同的输出)
//非纯函数 let min=18 let limit=age=>age>min //这个函数如果输入相同的age 但是外部改变了min 则会得到不同的结果 缺点:过分依赖于外部变量或者外部模块,导致系统的复杂性提高 //纯函数 let limit=(age,min)=>age>min //则如果age 和min相同的话 这个函数的输出值永远相同 -
高阶函数(函数作为参数传递给另一个函数,函数最为返回值被另一个函数返回)
function outfun(arg){
let a=18
return function(){
return arg+a
}
}
//也就是所谓的闭包
- 函数柯里化(传递给函数的一部分参数用于函数自身的功能调用,让该函数返回一个函数去处理其他的参数)
function add(x,y){
return x+y
}
//柯里化后
function add(x){
retrun function(y){
retrun x+y
}
}
- 组合函数(通过优雅的方式去实现纯函数的解耦) 组合函数可以理解是 定义一种函数参数都是函数 在这种函数中去执行传入的函数的方式
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
这种方式的有点就是每个函数都是单独的不会依赖环境中的变量 每个函数都可以单独的在不同环境下去使用