question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Add new `Document` node type

See original GitHub issue

It’s a lot of text, I wanted to include enough information. It is important for a front-end tooling ecosystem. But maybe it’s just a stylelint only problem with custom syntaxes ¯\_(ツ)_/¯

Custom syntaxes

PostCSS by default supports CSS in a form, where parsed file has only CSS. Most PostCSS syntaxes also for more classic CSS usage: SCSS, Sass, SugarSS, Less. However there are cases, when CSS is a part of other language. style tags and style attributes in HTML, Vue, Svelte. CSS-in-JS in JS template literals (Styled Components) or objects (JSS).

Currently stylelint supports both types of files: classic one file — one syntax, and the other one file — multiple syntaxes. It is done by huge work of @gucong3000. He made custom syntaxes to support multiple syntaxes in one file:

All this syntaxes are powered by postcss-syntax. This package does two jobs: automatically switch PostCSS syntax based on file extensions, and provides common tools for other syntaxes (more on this later).

These packages were developed only by him. Unfortunately he is not active on Github for the past two years. These packages are complex and intertwined together. It’s hard to understand how they work. No one else know how they work. I digged into them recently in an attempt to upgrade to PostCSS 8. Here’s my surface understanding (they my not be accurate).

postcss-syntax

postcss-syntax does two jobs. First job is documented in package’s readme: automatically switch PostCSS syntax based on file extensions. Second job is not documented, but very important for all other syntaxes: provide common tools for syntaxes. It introduces a new AST node type Document, but new AST node still has type: 'root', because it’s extended from PostCSS Root class. It does it by monkey-patching PostCSS via Node.js require.cache (crazy hack). For example for HTML document with two style tags we would have this kind of AST:

Document {
	nodes: [
		Root {
			nodes: [
				Rule {},
				AtRule {},
			]
		},
		Root {
			nodes: [
				Rule {},
				AtRule {},
			]
		},
	]
}

postcss-syntax makes sure that every PostCSS plugins are run on each Root.

Also it adds extra information to sources. Probably, for a successful stringifying.

Another issues with these syntaxes:

  • Implicit dependencies and code execution. postcss-syntax also calls custom syntax internal files, when postcss/syntax/load-syntax.js is called from custom syntax.
  • They use postcss internal files, which I believe is not allowed, because they are not part of official API.

Why it works this way

I don’t know exactly why postcss-syntax and dependent syntaxes architected this way.

However, I have an idea about some of behavior of these custom syntaxes. Each stylelint rule is a PostCSS plugin. These syntaxes were created with stylelint in mind. For many stylelint rules it makes more sense to have e. g. every styled component (const Element = styled.div``) as a separate root so a rule (PostCSS plugin) is run only on this piece of code.

For example we have following HTML:

<p style="color: red"></p>

<p style="color: blue"></p>

If we don’t distinguish them as separate Roots, rule like declaration-block-no-duplicate-properties would show a lint violation.

We can’t use Rule type for each style attribute, because we have many lint rules, which would check different aspects of Rule nodes (selectors, brackets, spacings), which would not be applicable for this fake Rule. In the mean time there is no stylelint rules, which has any specific behavior for a Root node.

Having postcss-syntax parse each entity as a separate Root, and they run plugins over each Root, allowed adoption of all this syntaxes in stylelint without changing hundreds of rules in stylelint codebase and in stylelint plugins.

What it’s all about

Custom syntaxes supported by stylelint and its plugins were in a rough state for the past two years. And usage of CSS in files, which are not CSS only, is increasing. It’s important for stylelint and PostCSS to support such cases. I would like to find a solution to this problem. postcss-css-in-js, postcss-html, postcss-markdown and postcss-syntax in they current form should be changed. To support PostCSS 8 and unblock community to make changes to this syntaxes, by refactoring and making code architecture more clear.

I think it’s important to find a vector which PostCSS and custom syntaxes should follow to support all types of CSS flavors modern development has.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:6
  • Comments:7 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
aicommented, Jan 3, 2021

@jeddy3 I do not have time to support these syntaxes. But we can move them to postcss org if the Stylelint team is OK with it.

0reactions
jeddy3commented, Jan 3, 2021

This is exciting stuff! I had one minor point to chime in on.

And recently we moved postcss-html and postcss-syntax to our organization to maintain them. We will release them under @stylelint namespace as well.

Like postcss-js and postcss-scss, it’d be great if these syntaxes lived in the PostCSS org (and were published outside of the stylelint NPM scope). These syntaxes are applicable to more than stylelint, e.g. https://github.com/postcss/postcss/issues/1494 which was for adding Tailwind to LitElement Web Components.

I was quickly digging into the process for NPM disputes and it turns out you already have ownership, @ai.

jeddy3@mac % npm owner ls postcss-syntax
ai <andrey@sitnik.ru>
gucong <gucong@gmail.com>
jeddy3@mac % npm owner ls postcss-jsx     
ai <andrey@sitnik.ru>
gucong <gucong@gmail.com>
jeddy3@mac % npm owner ls postcss-markdown
ai <andrey@sitnik.ru>
gucong <gucong@gmail.com>
jeddy3@mac % npm owner ls postcss-html    
ai <andrey@sitnik.ru>
gucong <gucong@gmail.com>

In hindsight, I should’ve checked this before we published our forks under the stylelint NPM scope a while back.

It’s a minor thing, but it’d be nice to tidy this up as I think it’d be healthy for the PostCSS ecosystem.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Node.nodeType - Web APIs - MDN Web Docs - Mozilla
The read-only nodeType property of a Node interface is an integer that identifies what the node is. It distinguishes different kind of nodes ......
Read more >
HTML DOM Element nodeType Property - W3Schools
Node Types ; 9, Document, Represents the entire document (the root-node of the DOM tree), Element, ProcessingInstruction, Comment, DocumentType ; 10, DocumentType ...
Read more >
Node properties: type, tag and contents
Let's get a more in-depth look at DOM nodes. ... We can append HTML to an element by using elem.innerHTML+="more html" . Like...
Read more >
Insert a Document — Node.js - MongoDB
You can specify additional query options using the options parameter. For more information on the method parameters, see the insertOne() API documentation ....
Read more >
Modifying Nodes, Content, and Values in an XML Document
A simple technique for changing the value of a node is to use node.Value = "new value"; . The following table lists the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found