Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use browser build of Sass or PostCSS compiler #88

Closed
eliot-akira opened this issue Mar 8, 2024 · 6 comments
Closed

Use browser build of Sass or PostCSS compiler #88

eliot-akira opened this issue Mar 8, 2024 · 6 comments

Comments

@eliot-akira
Copy link
Contributor

eliot-akira commented Mar 8, 2024

This would ensure compatibility with the newest Sass/CSS specification, and eliminate issues with the PHP port of the Sass compiler we're currently using, such as #82 and #93.

The official compiler is written in Dart but there's a browser build we could use.

The transition would involve moving the Sass compilation from the server to the template edit screen frontend, so that the compiled CSS is saved.

It's a question how to replace our current use of local Sass variables with CSS variables. The latter can't pass lists or maps, for example.

@eliot-akira eliot-akira changed the title Consider WebAssembly build of official Sass compiler Consider browser build of official Sass compiler Mar 10, 2024
@eliot-akira eliot-akira changed the title Consider browser build of official Sass compiler Use browser build of official Sass compiler Mar 15, 2024
@eliot-akira
Copy link
Contributor Author

eliot-akira commented Mar 15, 2024

As @nicolas-jaussaud found, SCSS-PHP 1.12 bumped up the required PHP version to 8.1. But we still need to support PHP 7.4 due to WordPress usage stats (which could be outdated).

That finalizes the decision to move away from SCSS-PHP, which has always been a bit problematic because of subtle incompatibilities and the need to chase a moving target, the Sass language specification. Using the offical compiler will ease the maintenance effort greatly.


A significant difference is that Sass will be compiled to CSS in the template edit screen before saving, instead of server side. That's better for performance, and probably how it should have been designed in the first place. But this removes our ability to pass Sass variables during template render.

We need to figure out how to achieve:

  • Passing values from template to CSS
  • Passing block control values to CSS

Some limitations of CSS variables:

  • They're global, so need to have unique prefix per template
  • They can only have primitive values (string, number) and not lists or maps

Ideally, I'd like to avoid bringing back the syntax like {{ variable }}, and also having to replace strings in the CSS during template render. Maybe it's possible with a creative use of CSS variables.

@eliot-akira
Copy link
Contributor Author

eliot-akira commented Mar 16, 2024

PostCSS is an alternative to Sass.

  • PostCSS is a tool for transforming styles with JS plugins. These plugins can lint your CSS, support variables and mixins, transpile future CSS syntax, inline images, and more.

Instead of a language, it's a CSS preprocessor that transforms code and extends its syntax. Recently I found:

That achieves "loops and logic" with CSS, so we can pass complex values like lists and maps.

An advantage to this approach is that it's simpler than trying to keep up with the entire Sass language specification. In recent years there were some breaking changes in the Sass syntax to adapt to modern CSS, and it doesn't feel as comfortable as before. In contrast, PostCSS stays close to standard CSS and (I think) integrates well with its modern features.

Another point in favor of PostCSS is that it's written in TypeScript, which I'm familiar with, instead of Sass that's written in Dart (and compiled to JavaScript).


About compiling to CSS in the browser instead of the server - maybe this one is possible:

  • Passing block control values to CSS

The template style can be compiled during block save, with control values passed as Sass/PostCSS variables.

But this:

  • Passing values from template to CSS

Values like post fields need to be fresh, so they must be passed as the template is rendered, not when it's saved. We might just have to make do with plain CSS variables with primitive values.

@eliot-akira eliot-akira changed the title Use browser build of official Sass compiler Use browser build of official Sass or PostCSS compiler Mar 16, 2024
@eliot-akira eliot-akira changed the title Use browser build of official Sass or PostCSS compiler Use browser build of Sass or PostCSS compiler Mar 16, 2024
@nicolas-jaussaud
Copy link
Contributor

I tried to test a little the PostCSS Advanced Variable plugin locally and it seems that it could work well for blocks variables!

A small issue I ran into is that while it's possible to use lists like in sass, I didn't find how to define and access maps with just this plugin (it's very possible that I just didn't find the correct syntax to do it)

I installed another plugin (postcss-map-get), and I was able to define and use maps using the same syntax that the one we currently use in blocks: map-get($map-variable, 'key') so it's probably not a problem

(Here is the code I used for my tests: postcss-variables-test.zip)

The only potential issue I can see with generating the block style when it's saved instead of during the render is for dynamic values (which are currently not supported in block controls but will be in the future)

At this point we will have saved values similar to Current user is [[user-id]] and they will need to be processed each time the block is rendered

It might not be a big deal as we can process the saved style with $fields->render_value( $current_block_css ); to render the dynamic values, but it assumes that PostCSS won't have any issue with the string we use for dynamic values as it might result in processing/generating invalid CSS for blocks because of it

@eliot-akira
Copy link
Contributor Author

Thank you for the feedback on PostCSS. I was exploring it recently and found the postcss-map-get plugin too, as well as post-css-nested and postcss-scss (which does not compile Sass but parses its syntax for transformation by plugins).

I see what you mean about dynamic field values, which have their own syntax.

[[dynamic_value_name::setting=value::setting2=value2]]

Good question if PostCSS can handle a value that's not valid CSS. If not, I wonder if it's possible to replace this syntax with regular CSS variables or the Sass-like "advanced variables".

Well, for dynamic values I imagine it's necessary to do string replacement on the compiled CSS. Even if we could replace it with CSS variables, it would still be limited to "primitive" values like string and number, not lists or maps.


So PostCSS and plugins can achieve a useful subset of Sass. I like that it's simpler, smaller, and more efficient to compile things on template save than during render.

OK, so I'll prepare a "CSS engine" with a curated set of PostCSS plugins. I imagine we can use this for the newly proposed Design module (TangibleInc/framework#1).

@eliot-akira
Copy link
Contributor Author

eliot-akira commented Mar 24, 2024

Here is the basis for a new CSS engine: https://github.com/TangibleInc/css

Thanks for the zip file, I converted your CSS code examples into test fixtures (here). I named the source files with extension .scss to get syntax highlighting in my editor.

The compiler is looking good, a small and useful subset of Sass features. I like how PostCSS is modular, it makes each feature independent and easier to understand.


On a related note, last week I started on a new HTML engine, based on unified and hast (Hypertext Abstract Syntax Tree format). Unified is a cool project, an ecosystem of tools for processing code and syntax trees.

The original motivation was that I'm not satisfied with the HTML formatter currently used in the code editor. That one is based on Prettier's HTML formatter, which in turn is based on Angular's old, big and complex HTML parser. I had to fork and customize it to make it work better with the L&L template language, but I didn't have a good grasp of the codebase.

The new HTML engine has a similar architecture like PostCSS, it's a pipeline of transformations, with each feature as a plugin. It's much easier to customize the details and extend the syntax.

In addition to formatting, I'm thinking of using it to save pre-parsed templates for performance gain. Another potential benefit is that this makes the template language more portable, so it could run with or without WordPress, in the browser (React, SQLocal) or server (Node, Bun).

Having full control of parse and render of HTML templates in the browser, it could also enable "structural editing", where the editor can switch between code and tree view for editing visually.

@eliot-akira eliot-akira mentioned this issue Apr 6, 2024
2 tasks
@eliot-akira
Copy link
Contributor Author

OK, I've prepared issue #101 to discuss further about migrating to the new CSS engine based on PostCSS.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants