case “strike”:

case “text”:

case “title”:

body += ${item.text}

break;

default:

throw Error(“error”, No corresponding treatment when item.type equal${item.type});

}

})

return body

}

}

md 转成抽象语树ast抽象语法数转成html字符串md2html-loader源码地址(https://github.com/6fedcom/fe-blog/blob/master/webpack-loader/loaders/md-loader.js)

loader的一些开发技巧

尽量保证一个loader去做一件事情,然后可以用不同的loader组合不同的场景需求 开发的时候不应该在 loader 中保留状态。loader必须是一个无任何副作用的纯函数,loader支持异步,因此是可以在 loader 中有 I/O 操作的。 模块化:保证 loader 是模块化的。loader 生成模块需要遵循和普通模块一样的设计原则。 合理的使用缓存 合理的缓存能够降低重复编译带来的成本。loader 执行时默认是开启缓存的,这样一来, webpack 在编译过程中执行到判断是否需要重编译 loader 实例的时候,会直接跳过 rebuild 环节,节省不必要重建带来的开销。但是当且仅当有你的 loader 有其他不稳定的外部依赖(如 I/O 接口依赖)时,可以关闭缓存:

this.cacheable&&this.cacheable(false);

loader-runner 是一个非常实用的工具,用来开发、调试loader,它允许你不依靠 webpack 单独运行 loadernpm install loader-runner --save-dev

// 创建 run-loader.js

const fs = require(“fs”);

const path = require(“path”);

const { runLoaders } = require(“loader-runner”);

runLoaders(

{

resource: “./readme.md”,

loaders: [path.resolve(__dirname, “./loaders/md-loader”)],

readResource: fs.readFile.bind(fs),

},

(err, result) =>

(err ? console.error(err) : console.log(result))

);

执行 node run-loader

认识更多的loader

style-loader源码简析

作用:把样式插入到DOM中,方法是在head中插入一个style标签,并把样式写入到这个标签的 innerHTML 里 看下源码。

先去掉option处理代码,这样就比较清晰明了了返回一段js代码,通过require来获取css内容,再通过addStyle的方法把css插入到dom里 自己实现一个简陋的style-loader.js

module.exports.pitch = function (request) {

const {stringifyRequest}=loaderUtils

var result = [

//1. 获取css内容。2.// 调用addStyle把CSS内容插入到DOM中(locals为true,默认导出css)

‘var content=require(’ + stringifyRequest(this, ‘!!’ + request) + ')’,

‘require(’ + stringifyRequest(this, ‘!’ + path.join(__dirname, “addstyle.js”)) + ')(content)’,

'if(content.locals) module.exports = content.locals’

]

return result.join(‘;’)

}

需要说明的是,正常我们都会用default的方法,这里用到pitch方法。pitch 方法有一个官方的解释在这里 pitching loader。简单的解释一下就是,默认的loader都是从右向左执行,用 pitching loader 是从左到右执行的。

{

test: /.css$/,

use: [

{ loader: “style-loader” },

{ loader: “css-loader” }

]

}

为什么要先执行style-loader呢,因为我们要把css-loader拿到的内容最终输出成CSS样式中可以用的代码而不是字符串。

addstyle.js

module.exports = function (content) {

let style = document.createElement(“style”)

style.innerHTML = content

document.head.appendChild(style)

}

babel-loader源码简析

首先看下跳过loader的配置处理,看下babel-loader输出上图我们可以看到是输出transpile(source, options)的code和map 再来看下transpile方法做了啥babel-loader是通过babel.transform来实现对代码的编译的, 这么看来,所以我们只需要几行代码就可以实现一个简单的babel-loader

const babel = require(“babel-core”)

module.exports = function (source) {

const babelOptions = {

presets: [‘env’]

}

return babel.transform(source, babelOptions).code

}

vue-loader源码简析

vue单文件组件(简称sfc)

{{a}}

webpack配置

const VueloaderPlugin = require(‘vue-loader/lib/plugin’)

module.exports = {

module: {

rules: [

{

test: /.vue$/,

loader: ‘vue-loader’

}

]

}

plugins: [

new VueloaderPlugin()

]

}

VueLoaderPlugin作用:将在webpack.config定义过的其它规则复制并应用到 .vue 文件里相应语言的块中。plugin-webpack4.js

const vueLoaderUse = vueUse[vueLoaderUseIndex]

vueLoaderUse.ident = ‘vue-loader-options’

vueLoaderUse.options = vueLoaderUse.options || {}

// cloneRule会修改原始rule的resource和resourceQuery配置,

// 携带特殊query的文件路径将被应用对应rule

const clonedRules = rules

.filter(r => r !== vueRule)

.map(cloneRule)

// global pitcher (responsible for injecting template compiler loader & CSS

// post loader)

const pitcher = {

loader: require.resolve(‘./loaders/pitcher’),

resourceQuery: query => {

const parsed = qs.parse(query.slice(1))

return parsed.vue != null

},

options: {

cacheDirectory: vueLoaderUse.options.cacheDirectory,

cacheIdentifier: vueLoaderUse.options.cacheIdentifier

}

}

// 更新webpack的rules配置,这样vue单文件中的各个标签可以应用clonedRules相关的配置

compiler.options.module.rules = [

pitcher,

…clonedRules,

…rules

]

获取webpack.config.js的rules项,然后复制rules,为携带了?vue&lang=xx…query参数的文件依赖配置xx后缀文件同样的loader 为Vue文件配置一个公共的loader:pitcher 将[pitchLoder, …clonedRules, …rules]作为webapck新的rules。

再看一下vue-loader结果的输出当引入一个vue文件后,vue-loader是将vue单文件组件进行parse,获取每个 block 的相关内容,将不同类型的 block 组件的 Vue SFC 转化成 js module 字符串。

// vue-loader使用@vue/component-compiler-utils将SFC源码解析成SFC描述符,根据不同 module path 的类型(query 参数上的 type 字段)来抽离 SFC 当中不同类型的 block。

const { parse } = require(‘@vue/component-compiler-utils’)

// 将单个*.vue文件内容解析成一个descriptor对象,也称为SFC(Single-File Components)对象

// descriptor包含template、script、style等标签的属性和内容,方便为每种标签做对应处理

const descriptor = parse({

source,

compiler: options.compiler || loadTemplateCompiler(loaderContext),

filename,

sourceRoot,

needMap: sourceMap

})

// 为单文件组件生成唯一哈希id

const id = hash(

isProduction

? (shortFilePath + ‘\n’ + source)

: shortFilePath

)

// 如果某个style标签包含scoped属性,则需要进行CSS Scoped处理

const hasScoped = descriptor.styles.some(s => s.scoped)

然后下一步将新生成的 js module 加入到 webpack 的编译环节,即对这个 js module 进行 AST 的解析以及相关依赖的收集过程。

来看下源码是怎么操作不同type类型(template/script/style)的,selectBlock 方法内部主要就是根据不同的 type 类型,来获取 descriptor 上对应类型的 content 内容并传入到下一个 loader 处理这三段代码可以把不同type解析成一个import的字符串

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前! 因此收集整理了一份《2024年Web前端开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注:前端)

结尾

学习html5、css、javascript这些基础知识,学习的渠道很多,就不多说了,例如,一些其他的优秀博客。但是本人觉得看书也很必要,可以节省很多时间,常见的javascript的书,例如:javascript的高级程序设计,是每位前端工程师必不可少的一本书,边看边用,了解js的一些基本知识,基本上很全面了,如果有时间可以读一些,js性能相关的书籍,以及设计者模式,在实践中都会用的到。

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

高级程序设计,是每位前端工程师必不可少的一本书,边看边用,了解js的一些基本知识,基本上很全面了,如果有时间可以读一些,js性能相关的书籍,以及设计者模式,在实践中都会用的到。

1710701681871)]

结尾

学习html5、css、javascript这些基础知识,学习的渠道很多,就不多说了,例如,一些其他的优秀博客。但是本人觉得看书也很必要,可以节省很多时间,常见的javascript的书,例如:javascript的高级程序设计,是每位前端工程师必不可少的一本书,边看边用,了解js的一些基本知识,基本上很全面了,如果有时间可以读一些,js性能相关的书籍,以及设计者模式,在实践中都会用的到。

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

高级程序设计,是每位前端工程师必不可少的一本书,边看边用,了解js的一些基本知识,基本上很全面了,如果有时间可以读一些,js性能相关的书籍,以及设计者模式,在实践中都会用的到。

相关阅读

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: