This is the first day of my participation in the August More Text Challenge.

preface

Through this article you will learn:

  • What is Vue Scoped?
  • Vue scoped?
  • Vue Scoped principle?
  • How is the data-V-XXX attribute generated on the rendered HTML tag?
  • How is the property selector added to the CSS code implemented?

What is?

On the style tag in the Vue file, there is a special attribute: scoped. When a style tag has the scoped attribute, its CSS style applies only to the current component; that is, the style applies only to the current component element. With this property, styles between components can be kept from contaminating each other. If all style tags in a project are scoped, the style is modularized.

role

Style isolation, style modularization.

Light into the principle of

  • Each Vue file will correspond to a unique ID, which will be generated from the file pathname and hash content, combined to form a scopeId.

  • When the template tag is compiled, the scopeId of the current component is added to each tag, as in:

<div class="demo">test</div> <div class="demo" data-V-12e4e11e >test</div>Copy the code
  • When the style tag is compiled, it outputs the style based on the scopeId of the current component through the property selector and the composition selector, such as:
.demo{color: red; }.demo[data-v-12e4e11e]{color: red; }Copy the code

This pretty much adds a unique representation to our configured style.

However, there are two problems:

  • How is the data-V-XXX attribute generated on the rendered HTML tag?
  • How is the property selector added to the CSS code implemented?

With the question, we move on.

Knowledge reserve (can be skipped)

Before we go further, let’s reserve some relevant knowledge: resourceQuery, Loader. pitch, VueLoaderPlugin. (If you are impatient, skip the current section and start directly with vue-loader.)

1. resourceQuery

The function of resourceQuery is to combine different Query parameters in vue-loader according to the matching path of imported file path parameters and allocate labels to corresponding Loader for processing by resourceQuery.

{ test: /.css$/, resourceQuery: /inline/, use: 'url-loader'} // Loader import Foo from './foo.css? inline'Copy the code

2. loader.pitch

Normally, loader executes from right to left, but the pitch method on Loader is called from left to right before executing from right to left. Such as:

module.exports = {
//...
module: {
    rules: [
      {
//...
        use: ['a-loader', 'b-loader', 'c-loader'],
      },
    ],
  },
};
Copy the code

These steps will occur:

|- a-loader `pitch` |- b-loader `pitch` |- c-loader `pitch` |- requested module is picked up as a dependency |- c-loader  normal execution |- b-loader normal execution |- a-loader normal executionCopy the code

What can I do in the pitching phase? First, the data passed to the pitch method is also exposed to this.data during execution and can be used to capture and share previous information during the loop.

module.exports = function (content) {
  // this.data.value = 42
  return someSyncOperation(content, this.data.value);
};
module.exports.pitch = function (remainingRequest, precedingRequest, data) {
  data.value = 42;
};
Copy the code

Second, if one loader gives a result in the pitch method, the process goes back and skips the rest of the loader. In our example above, if the PITCH method of the B-loader returns something:

module.exports = function (content) {
  return someSyncOperation(content);
};
module.exports.pitch = function (remainingRequest, precedingRequest, data) {
  if (someCondition()) {
    return (
      'module.exports = require(' +
      JSON.stringify('-!' + remainingRequest) +
      ');'
    );
  }
};
Copy the code

The above steps will be shortened to:

|- a-loader `pitch`
  |- b-loader `pitch` returns a module
|- a-loader normal execution
Copy the code

3. VueLoaderPlugin

The VueLoaderPlugin does two main things:

  • One is a registered public pitcher.
  • One is to copy the rules of Webpack.

vue-loader

With resourceQuery, Loader. pitch, and VueLoaderPlugin in mind, let’s look at what vue-Loader does.

pitcher

The loader that injects the corresponding label according to query.type. Since loader.pitch is executed before loader, it is executed during the capture phase, checking Query.type and calling the relevant Loader directly.

  • Type = style, execute stylePostLoader
  • Type = template to execute templateLoader

Two key loaders are introduced here: stylePostLoader and templateLoader, which will be covered in two separate sections below.

prepare

This step is mainly to do some preparatory work.

  1. Generates a unique hash ID for a single file.

2. Process the template tag and concatenate the query parameters3. Process the style label and concatenate parameters such as type=style for each label After the preparation is done, the unused type calls the unused Loader for processing. The first is the template processing, templateLoader.

templateLoader

Render generates a VNode, which describes the corresponding HTML tags and structures of the component. A VNode contains the basic attributes needed to render a DOM node. Of course, the base property here also includes scopeId. So how did the scopeId end up in DOM? In templateloader.js, when the template file scopre=true generates a scopeId based on the unique hash ID of the single file.

The next step is to use the template compiler to generate the familiar VNode. In this process, the configuration properties are processed. In this process, scopeId is resolved to the configuration properties of the VNode. CreateElement is then called when the render function executes, which is rendered to the DOM node as the original property of the VNode. Which answers the first question.”How is the data-V-XXX attribute generated on the rendered HTML tag?“.

stylePostLoader

TemplateLoader solves the problem of ID rendering DOM, while stylePostLoader is used to add property selectors to Css. Generate an ID in stylePostLoader.js, the style in the same single-page component, consistent with the scopeId in templateLoader.The content of the style tag is then parsed via PostCSS, and the scopedPlugin appends a [scopeId] property selector to each selector.There will also be some special treatment for scoped. The property selector for [scopeId] will not be appended for special selectors such as ‘>>>’, ‘/deep/’, :: V-deep, pseudo, etc.

To answer the second question mentioned earlier in this article, “How are property selectors added to CSS code implemented?” InsertAfter adds a property selector to each selector under the current styles, whose value is the [scopeId] passed in.

CSS scoped effect is achieved because the same property exists only on the DOM node rendered by the current component.

conclusion

This paper briefly analyzes the underlying implementation principle of Vue Scoped. Vue -loader generates the hash ID and calls different loaders according to the type to inject the hash ID into the DOM and property selector respectively. Implements CSS local scoped effects. CSS Scoped can be considered as a Vue custom solution for handling native CSS scopes.

That’s all for this article. Thanks for watching, and if you still like it, please give it a thumbs up. Thanks.

reference

  • www.jb51.net/article/140…

  • www.webpackjs.com/configurati…

  • vue-loader.vuejs.org/

  • www.jb51.net/article/170…

  • Webpack.js.org/api/loaders…

  • Github.com/postcss/pos…

  • www.jb51.net/article/140…

  • Github.com/vuejs/vue-c…

  • vue-loader-v14.vuejs.org/zh-cn/

  • Github.com/vuejs/vue-l…