如何加载CSS文件
当前我们的打包器可以把多个文件打包到一个js文件中去,现在我们要支持当import xxx.css文件要可以生效。先来看一下我们目前的思路。
当前
- 当前的
bundler只能打包js文件 - 我们想要加载
css文件
目标
如果我们把css文件变成js,那么是不是可以加载css文件了呢?我们顺着这个思路开始在之前的代码中继续编写。我们只需要在读取到css文件之后修改文件里面的内容如下
let code = readFileSync(resolve(filepath)).toString()
//判断是.css结尾的文件
if(/\.css$/.test(filepath)){
code = `
const str = ${JSON.stringify(code)}
//如果document存在,就动态创建一个style标签插入到head里面
if(document){
const style = document.createElement('style')
style.innerHTML = str
document.head.appendChild(style)
}
export default str
`
}
//把读取到的es6代码先进行转换成es5的
const { code: es5Code } = babel.transform(code, {
presets: ['@babel/preset-env']
})
测试
在当前项目下面新建project-css
新增index.js
console.log(12342423)
import './style.css'
新增style.css
body{
color: rebeccapurple;
}
新增index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>Css加载成功</h1>
<script src="dist.js"></script>
</body>
</html>
修改bundler_css.ts里面的入口文件和出口文件
//设置项目根目录
const projectRoot = resolve(__dirname, 'project-css')
writeFileSync('./project-css/dist.js', generateCode())
运行以下命令
npx ts-node bundler_css.ts
会在project-css文件夹下面生成dist.js文件。
我们在浏览查看
index.html
如果你看到了当前的效果说明你的打包器现在已经支持打包
.css文件啦。
创建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文件,接着我们想,可不可以将处理css代码的这块逻辑分离出去呢?带着这个思路,我们继续开始。
+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
拷贝一份之前的打包器文件,进行修改,如下,同样也可以实现之前的功能,不一样的地方就在于把css转换成js和把style代码加入到head里面的代码与打包器的代码进行了分离。仅此而已
let code = readFileSync(resolve(filepath)).toString()
//判断是.css结尾的文件
if(/\.css$/.test(filepath)){
code = require('./loaders/css-loader.js')(code)
}
//把读取到的es6代码先进行转换成es5的
const { code: es5Code } = babel.transform(code, {
presets: ['@babel/preset-env']
})
发现打包器的问题
单一职责原则
webpack里面的loader只做一件事情,现在我们的css-loader做了两件事情
- 把
css转成了js字符串。 - 把
js字符串放到了style标签里面。
所以我们试图把现在的css-loader拆成两个css-loader和style-loader
css-loader
const transform = code => code
module.exports = transform
style-loader
const transform = code => `
if (document) {
const style = document.createElement('style')
style.innerHTML = ${JSON.stringify(code)}
document.head.appendChild(style)
}
`
module.exports = transform
我们检测到如果是.css结尾的就把文件内容当做字符串保存起来,接下来调用style-loader把这段字符串插入到页面里面就可以了。
let code = readFileSync(resolve(filepath)).toString()
//判断是.css结尾的文件
if(/\.css$/.test(filepath)){
code = require('./loaders/css-loader.js')(code)
code = require('./loaders/style-loader.js')(code)
}
//把读取到的es6代码先进行转换成es5的
const { code: es5Code } = babel.transform(code, {
presets: ['@babel/preset-env']
})
loader面试题
webpack的loader是什么?
webpack自带的打包功能支持打包js文件。- 在我们项目中要想加载
css/less/ts/md文件的时候,就需要用到loader了 loader的原理就是把文件内容包装成能够运行的js比如- 加载
css的时候就需要用到css-loader和style-loader css-loader负责把css源代码变成export default str的js代码形式。style-loader负责把源码挂载到head里面的style标签里