Webpack之loader

前言

基于上次实现的简易打包器,我们只需在获取文件的位置区分是js文件还是css文件,如果是css文件则走css相关逻辑。

核心代码:

let code = readFileSync(filepath).toString()
  if(/\.css$/.test(filepath)){ 
    code = `
      const str = ${JSON.stringify(code)}
      if(document){
        const style = document.createElement('style')
        style.innerHTML = str
        document.head.appendChild(style)
      }
      export default str
    ` 
  }
  const { code: es5Code } = babel.transform(code, {
    presets: ['@babel/preset-env']
  })

 

打造一个css-loader

什么是loader?简单的说就是一个函数。

一个 loader 可以是一个普通函数:

function transform(code){
  const code2 = doSomething(code)
  return code2
}
module.exports = transform // 用 module 是为了兼容 Node.js

一个 loader 也可以是一个异步函数:

async function transform(code){
  const code2 = await doSomething(code)
  return code2
}
module.exports = transform // 旧版本 Node.js 不支持 export 关键字

我们将前言中的核心代码提取到css-loader.js文件中,再引用css-loader.js:

  // 获取文件内容,将内容放至 depRelation
  let code = readFileSync(filepath).toString()
  if(/\.css$/.test(filepath)){ // 如果文件路径以 .css 结尾
    // 就把css改造成js,并自动加载到head里
    // 用require而不用import主要是为了方便动态加载
    code = require('./loaders/css-loader.js')(code)
  }
 

css-loader.js

const transform = code => `
const str = ${JSON.stringify(code)}
if(document){
  const style = document.createElement('style')
  style.innerHTML = str
  document.head.appendChild(style)
}
export default str
`
module.exports = transform

 

单一职责原则

上一步的css-loader.js,其实是做了两件事情:

  1. 将CSS导出为js
  2. 再将CSS代码在指定时间插入到指定代码中

我们按道理最好将这两步分成两个loader,这样更易于后期的扩展。

css.loader

const code = code => `
const str = ${JSON.stringify(code)}
export default str
`
module.exports = code

style.loader

import code form css.loader
const transform = code => `
if(document){
  const style = document.createElement('style')
  style.innerHTML = code
  document.head.appendChild(style)
}
`
module.exports = transform

但是这样会有问题,问题在哪?

style-loader 不是转译

sass-loader、less-loader 这些 loader 是把代码从一种语言转译为另一种,因此将这样的 loader 连接起来不会出问题。

但 style-loader 是在插入代码,不是转译,所以需要寻找插入时机和插入位置,插入代码的时机应该是在获取到 css-loader 的结果之后,插入代码的位置应该是在旧代码的下面。

 

遇到困难,查看Webpack源码是如何做的

Webpack 官方 style-loader(源码) 的思路:

  • style-loader 在 pitch 钩子里通过 css-loader 来 require 文件内容
  • 然后在文件内容后面添加 injectStylesIntoStyleTag(content, ...) 代码
  • 官方style.loader比我们的style.loader多了一个传参request,这样用户可以传入自定义事件,保证插入时间以及方式。
loaderApi.pitch = function loader(request) {......}

 

loader总结

  • webpack 自带的打包器只能支持 JS 文件
  • 当我们想要加载 css/less/scss/stylus/ts/md 文件时,就需要用 loader loader 的原理就是把文件内容包装成能运行的 JS
  • 例如加载 css 需要用到 style-loader 和 css-loader,
  • css-loader 把代码从 CSS 代码变成 export default code 形式的 JS 代码
  • style-loader 把代码挂载到 head 里的 style 标签里
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值