How do I load a CSS file

Currently our packager can package multiple files into a js file, now we need to support this when importing xxx. CSS files. Let’s take a look at our current thinking.

The current

  • The currentbundlerCan only be packagedjsfile
  • We want to loadcssfile

The target

If we change the CSS file to JS, can we load the CSS file? Let’s start with this idea and continue writing in the same code as before. We just need to change the contents of the CSS file after we read it

 let code = readFileSync(resolve(filepath)).toString()
  // Determine if it is a.css ending file
  if(/\.css$/.test(filepath)){
    code = `
     const str = The ${JSON.stringify(code)}// If document exists, If (document){const style = document.createElement('style') style.innerhtml = STR document.head.appendChild(style) } export default str `
  }
  // Convert es6 code to ES5 code first
  const { code: es5Code } = babel.transform(code, {
    presets: ['@babel/preset-env']})Copy the code

test

Create a new project-css under the current project

The new index. Js

console.log(12342423)
import './style.css'
Copy the code

The new style. The CSS

body{
  color: rebeccapurple;
}
Copy the code

The new index. HTML

<! DOCTYPEhtml>
<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>The Css is loaded successfully.</h1>
  <script src="dist.js"></script>
</body>
</html>
Copy the code

Modify the entry and exit files in bundler_css.ts

// Set the project root directory
const projectRoot = resolve(__dirname, 'project-css')

writeFileSync('./project-css/dist.js', generateCode())
Copy the code

Run the following command

 npx ts-node bundler_css.ts
Copy the code

The dist. Js file is generated under the project-css folder.

We’re just browsingindex.html

If you see the current effect, your wrapper now supports packaging.cssFile.

Create CSS Loader

First of all

What does loader look like?

  • aloaderIt could be an ordinary function
function transform(code){
  const code2 = doSomething(code)
  return code2
}
module.exports = transform // Module is used for node.js compatibility
Copy the code
  • aloaderIt can also be an asynchronous function
async function transform(code){
  const code2 = await doSomething(code)
  return code2
}
module.exports = transform // Older versions of Node.js do not support the export keyword

Copy the code

– The hyphen indicates a connection, and the underscore indicates an interval.

Having succeeded in getting the wrapper to support CSS files above, we wondered if we could separate out the logic that handles the CSS code. With that in mind, let’s start.

+loaders/css-loader.js

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

module.exports = transform
Copy the code

Make a copy of the previous wrapper file and modify it, as shown below. The same function can be implemented, but the difference is that the code to convert THE CSS to JS and add the style code to the head is separated from the wrapper code. That’s all

 let code = readFileSync(resolve(filepath)).toString()
  // Determine if it is a.css ending file
  if(/\.css$/.test(filepath)){
    code = require('./loaders/css-loader.js')(code)
  }
  // Convert es6 code to ES5 code first
  const { code: es5Code } = babel.transform(code, {
    presets: ['@babel/preset-env']})Copy the code

Found a problem with the packer

Single responsibility principle

The Loader in WebPack only does one thing, and now our CSS-Loader does two things

  1. thecssInto thejsA string.
  2. thejsThe string is instyleInside the label.

So we try to split the current CSS-loader into two CSS-loaders and style-loaders

css-loader

const transform = code= > code

module.exports = transform
Copy the code

style-loader

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

If we detect a.css ending, we save the contents of the file as a string and then use the style-loader to insert the string into the page.

 let code = readFileSync(resolve(filepath)).toString()
  // Determine if it is a.css ending file
  if(/\.css$/.test(filepath)){
    code = require('./loaders/css-loader.js')(code)
    code = require('./loaders/style-loader.js')(code)
  }
  // Convert es6 code to ES5 code first
  const { code: es5Code } = babel.transform(code, {
    presets: ['@babel/preset-env']})Copy the code

Loader interview questions

What is the Loader for WebPack?

  1. webpackThe built-in packaging function supports packagingjsFile.
  2. In our project we want to loadcss/less/ts/mdYou need it when you file itloaderthe
  3. loaderThe idea is to wrap the contents of a file into something that worksjs

Such as

  1. loadingcssYou need to use itcss-loaderandstyle-loader
  2. css-loaderResponsible for thecssThe source code becomesexport default strthejsCode form.
  3. style-loaderResponsible for mounting the source code toheadThe inside of thestyleIn the label