Original address: hiihl.com/articles/20…

This article is about the interpretation of less-loader in the source guide series of Webpack Loader. It mainly describes the work of Loader. The content of less compilation will be explained separately in the future.

Source structure

Source code v4.0.5, SRC directory as follows:

src
|____cjs.js
|____createWebpackLessPlugin.js
|____formatLessError.js
|____getOptions.js
|____index.js
|____processResult.js
|____removeSourceMappingUrl.js
|____stringifyLoader.js
Copy the code

The options that

GetOptions (loaderContext) is a loaderContext that combines the WebPack configuration with the Query or options configuration of the loader

  • The paths module parses paths, which default to webpack resolvers, and must be an array of absolute paths. For example, in less we want to refer to the bootstrap less file in node_modules@import "~bootstrap/less/bootstrap";The default module resolution will be the same as WebPack, but if Loader configures Paths, webPack’s resolution path and alias configuration will not be valid here.
  • Plugins array, plugins used at compile time, see plugins for existing plugins
  • SourceMap source mapping, which needs to be configured with CSS-Loader; The value can be Boolean or object. The sourceMap configuration is as follows:
    • {String} sourceMapFilename, which corresponds to the –source-map option in LessC whose attribute value is String;
    • {String} sourceMapRootPath, corresponding to lessC’s — source-map-rootPath option;
    • {String} sourceMapURL, corresponding to lessC’s –source-map-url option;
    • {String} sourceMapBasePath, corresponding to lessC’s –source-map-basepath option;
    • {Boolean} sourceMapLessInline corresponds to lessC’s –source-map-less-inline option;
    • {Boolean} sourceMapMapInline corresponds to lessC’s –source-map-map-inline option;
    • {Boolean} outputSourceFiles corresponds to lessC’s –source-map-map-inline option; Pay attention toThis value is set to true by default in less-loader.

For other less-loader configurations, you can view the configuration options of less and switch them to the hump mode.

There are two important configurations: globalVars and modifyVars. These are used to add or modify less variables, as an example.

main.less

@import "./other.less";

.box:extend(.hotpink) {
  width: @boxWidth;
  height: @boxHeight;
}
Copy the code

other.less

@boxHeight: 10px;

.hotpink {
  background: hotpink;
  width: @boxWidth;
}
Copy the code

In the example above, @boxheight is defined in other.less and is used in main.less with a value of 10px; @boxWidth is used in main.less and other.less, but not defined; Now we configure it in webpack.config.js

{
  loader: "less-loader".query: {
    sourceMap: true.globalVars: {
      "boxWidth": '200px'
    },
    modifyVars: {
      "boxHeight": '200px'}}}Copy the code

In the end, no errors were compiled, resulting in

.hotpink..box {
  background: hotpink;
  width: 200px;
}
.box {
  width: 200px;
  height: 200px;
}
Copy the code

In this example, globalVars is equivalent to adding @boxWidth: 200px to the top of each less file, so the compiled width is 200px, while modifyVars is equivalent to adding @boxheight to the bottom of each file: 200px, which overwrites the existing @boxheight: 10px, so the compiled height is 200px instead of 10px;

What does that do? With these two configuration items, we can extract some of the styles from variables and combine them into different themes, such as default.less

@primary-color: #003cee;
Copy the code

themes/pink.js

module.exports = {
  "@primary-color": 'pink'
};
Copy the code

webpack.config.js

{
  loader: 'less-loader'.query: {
    modifyVars: require('./themes/pink')}}Copy the code

Render = function (input, options, callback); render = function (input, options, callback); If callback is not passed, the render method returns a promise.

Compilation result processing

See how processResult.js handles the compiled results, resultPromise is the promise returned by the aforementioned Render.

function processResult(loaderContext, resultPromise) {
  const { callback } = loaderContext;

  resultPromise
    .then(({ css, map, imports }) = > {
      imports.forEach(loaderContext.addDependency, loaderContext);
      return {
        // Removing the sourceMappingURL comment.
        // See removeSourceMappingUrl.js for the reasoning behind this.
        css: removeSourceMappingUrl(css),
        map: typeof map === 'string' ? JSON.parse(map) : map,
      };
    }, (lessError) => {
      throw formatLessError(lessError);
    })
    .then(({ css, map }) = > {
      callback(null, css, map);
    }, callback);
}
Copy the code

The compiled results include CSS, Map, and imports. CSS is the CSS content compiled by less, Map is the sourceMap information, and imports are all dependent file paths during compilation. The first step is to call addDependency to add all the imports files to the dependency. This method will start compiling updates when the dependencies change in Watch mode. Then there is removeSourceMappingUrl(CSS), which removes sourceMappingURL= from the result because less-loader has no way of knowing where the final sourceMap will be. Finally, callback(NULL, CSS, map) is called to pass the result to the next loader for execution, and the less-loader is complete.

In the next article we will continue to look at how CSS-Loader continues to process the results of less-Loader compilation.