1

About style compilation

Because the idea of webpack compilation is JS for nothing, it means that all resource files associated with web projects can be linked through js. However, because of pictures and styles that were not compatible with JS Baganzi, there are various loaders to solve their relevance problems;

When it comes to webpack style compilation, there are always several loaders that cannot be missed, such as less-loader, css-loader, style-loader, and the last common configuration:

const lessLoader = {
  test: /\.less$/,
  use: [
    'style-loader',
    {
      loader: 'css-loader',
      options: {
        modules: true,
      },
    },
    'less-loader',
  ],
}

The above file tells webpack that when it encounters a file with a file name ending in .less, first compile with less-loader, then compile with css-loader, and finally use style-loader. I used to use such a js pseudo code to outline :

// 伪代码
const res = styleLoader(cssLoader(lessLoader('xxx.less')));

In fact, this pseudo code is not rigorous at all.

Both are loaders, but their functions are quite different

style-loader is actually different from css-loader and less-loader . The latter is actually responsible for modularity and grammar translation; while style-loader (and the commonly used mini-css-extract-plugin) is responsible for adhesion The agent function is to load the css in js into html to make the style effective;

20210802224636

Feel free to be more rigorous pseudo-code should be written like this:

const cssContent = cssLoader(lessLoader('xxx.less'));
// 通过styleTag插入css 字符串到head中
styleLoader(cssContent,  document.head);

It seems that the article should be over at this point, but in fact the good show just started.

I used to think that style-loader inserted the style into the html when it was built, but in fact I was wrong, and the mistake was five years (what you thought was but your ignorance: give it to yourself), correct The answer is that the css is built into the js file, and then when the js file is loaded, it is loaded into the html style-loader

Simply put, I used to think that this loader was a build time, but it was actually a runtime.

How to judge it is very simple. Just like how to judge whether a website is server-side rendering, check whether the html file requested by the homepage of the website contains styles (you can also view the html file directly through the source panel, not elements).

The reason for this misjudgment is that I directly translated the mini-css-extract-plugin . This plugin stripped the style in JS to form a new file, and then inserted the style address into the html header. This is a complete Full build time.

And why we suddenly pay attention to this point recently is because we are adjusting a micro-component program. When the component is successfully loaded, we find that the style is missing. Take a look at the horrible picture below:
20210803081706

After debugging, it was found that the style was indeed packaged into the file, but it was not loaded into the style tag. The first instinct was the lack of loader. Then I checked the build tool and found that the style compilation configuration only css-loader the level of style-loader , lacking 06108b14203b03.

Look at the style loading process from the build results

If this article is over, it seems to be too unlike me. After all, I am the real me who asks (xuxudaodao). Next, through a piece of example code, let's see how webpack builds and how to load styles.

Sample code:

// style.less代码
@font-size: 28px;

.Demo {
  box-sizing: border-box;
  :global {
    .demo-title {
      font-size: @font-size;
    }
  }
}
import React from 'react';
// 引入样式
import style from './style.less';

export default function Demo() {
  return (
    <div className={style.Demo}>
      <h3 className="emo-title">this is a demo</h3>
    </div>
  );
}

Then through webpack, the style-loader is used to build, for the convenience of reading, no code compression and uglification are done.

Then you can see from the entrance that the style is imported like this:

// 注释无用代码有删减
__webpack_require__.d(__webpack_exports__, "default", function() { return Demo; });
var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react");
var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
// 引入样式
var _style_less__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__("./src/demo/style.less");
var _style_less__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_style_less__WEBPACK_IMPORTED_MODULE_1__);


function Demo() {
  return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
    className: _style_less__WEBPACK_IMPORTED_MODULE_1___default.a.Demo
  }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("h3", {
    className: "emo-title"
  }, "this is a demo"));
}

As you can see, in the entry file, there is a ./src/demo/style.less module and assigned to the _style_less__WEBPACK_IMPORTED_MODULE_1___default variable;

Then follow the vine and continue to see what the style.less module looks like:

// "./src/demo/style.less" 模块
function(module, exports, __webpack_require__) {
  var api = __webpack_require__("../../../../.def/def_modules/.builders/@ali/builder-cook/node_modules/_style-loader@1.3.0@style-loader/dist/runtime/injectStylesIntoStyleTag.js");
  var content = __webpack_require__("../../../../.def/def_modules/.builders/@ali/builder-cook/node_modules/_css-loader@1.0.1@css-loader/index.js?!../../../../.def/def_modules/.builders/@ali/builder-cook/node_modules/_postcss-loader@3.0.0@postcss-loader/src/index.js?!../../../../.def/def_modules/.builders/@ali/builder-cook/node_modules/_less-loader@6.2.0@less-loader/dist/cjs.js?!./src/demo/style.less");
  content = content.__esModule ? content.default : content;

  if (typeof content === 'string') {
    content = [[module.i, content, '']];
  }

  var options = {};
  options.insert = "head";
  options.singleton = false;

  var update = api(content, options);
  module.exports = content.locals || {};
}

This piece of code can be seen that this module is a link (introduced by css) and next (inserted in html);

less-loader/dist/cjs.js?!./src/demo/style.less by importing from the module 06108b14203cf3, and inserting html is by injectStylesIntoStyleTag . From the method name, you can know that his role is to insert css styles through the style tag.

There is another point in this, that is, the final export. The module finally exports content.locals, and continue to see what content is based on the clues:

function(module, exports, __webpack_require__) {
  exports = module.exports = __webpack_require__("../../../../.def/def_modules/.builders/@ali/builder-cook/node_modules/_css-loader@1.0.1@css-loader/lib/css-base.js")(false);

  exports.push([module.i, "._1rfoVjSya7b-iuQB2_qKPh {\n  -webkit-box-sizing: border-box;\n          box-sizing: border-box;\n}\n._1rfoVjSya7b-iuQB2_qKPh .demo-title {\n  font-size: 28px;\n}\n", ""]);

  exports.locals = {
    "Demo": "_1rfoVjSya7b-iuQB2_qKPh"
  };
}

Through the above code, we can see that exports.locals is the modularity of CSS

At this point, the truth is revealed...

Write at the end

I seem to particularly enjoy this ruozhi detective feeling, which opened up a black box for me before, and in the end it was the same sentence, there is really no black demonization in the front end, basically it is a red book. As long as you can calm down and savor the knowledge inside: magic is just a particularly good idea after all.

公众号:前端黑洞


前端黑洞
3.5k 声望4.7k 粉丝

不要假装很努力,因为结果不会陪你演戏