Loader 原理

2021-09-28  本文已影响0人  sweetBoy_9126

针对上一篇文章我们的 bundler 只能加载 js,那么我们如何让它支持 css 那?

思路:
1). 我们的 bundler 只能加载 js
2). 我们想要加载 css
如果我们能把 css 变成 js, 那么就可以加载 css 了

1. 把 css 变成 js

复制 bundler_1.ts 为 bundler_css.ts

let code = readFileSync(filepath).toString()
if (/\.css$/.test(filepath)) {
    code = `
      const str = ${JSON.stringify(code)}
      export default str
    `
  }

问题:上面的代码把 body {color: red} 变成
const str = "body {color: red}"; export default str
有什么 X 用?body 里的文字并不会变红啊

1.1 改进

if (/\.css$/.test(filepath)) { // 如果文件路径以 .css 结尾
    code = `
      const str = ${JSON.stringify(code)}
+      if (document) {
+        const style = document.createElement('style')
+        style.innerHTML = str
+        document.head.appendChild(style)
+      }
      export default str
    `
  }

测试复制 project_1 为 project_css
新建一个style.css 文件,然后在index.js 里引入

body {
    color: red;
}

运行 node -r ts-node/register bundler_css.ts
然后直接在 dist 目录下创建 index.html 引入打包生成的文件

解决过程

  1. project_1 目录复制为 project_css
  2. bungler_1.ts 复制为 bundler_css.ts
  3. 改一下 bundler_css.ts
  4. 改一下 project_css 让 index.js 加载一个 css 文件
  5. 创建 index.html 测试 css 是否生效

2. 创建 css-loader

将上面的 code 代码抽离为单独的 loader

  1. 新建一个 loaders/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
  1. 复制一个 bundler_css.ts 并命名为 bundler_css_loader.ts
    将代码改为
if (/\.css$/.test(filepath)) {
    code = require('./loaders/css-loader.js')(code)
  }

2.1. 什么是 loader

1). loader 可以是一个普通函数

function transform(code) {
  const code2 = doSomething(code)
  return code2
}
module.exports = transform

2). loader 也可以是一个异步函数

async function transform(code) {
  const code2 = await doSomething(code)
  return code2
}
module.exports = transform

核心代码


为什么用 require 不用 import

3. 优化 loader

单一职责原则
webpack 里每个 loader 只做一件事
而我们的 css-loader 做了两件事:
1). 把 css 变为 js 字符串
2). 把 js 字符串放到 style 标签里

将我们的 loader 拆成 2 个
新建一个 style-loader

const transform = (code) => `
  if (document) {
    const style = document.createElement('style')
    style.innerHTML = ${JSON.stringify(code)}
    document.head.appendChild(style)
  }
  export default str
`
module.exports = transform
const transform = (code) => `
  const str = ${JSON.stringify(code)}
  export default str
`
module.exports = transform
if (/\.css$/.test(filepath)) {
    code = require('./loaders_2/css-loader.js')(code)
    code = require('./loaders_2/style-loader.js')(code)
  }

运行 node -r ts-node/register bundler_css_loader2.ts
打包编译的代码如下

style.innerHTML 里多了很多我们不需要的代码,实际上我们只想要 style.innerHTML = "{color: red}"

3.1. 问题分析

上一篇 下一篇

猜你喜欢

热点阅读