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.

Extended `@block` Reference Syntax

See original GitHub issue

Summary

Implementation of this proposal will enable the following features:

  • Rename @block-reference to @block
  • Additions to the @block import syntax
    • Default @block imports from a Block module
    • Named @block imports from a Block module
    • Default Block exports from a module
    • Named Block exports from a module
  • default as a reserved name
  • css-blocks package.json config field
    • Custom Block module “main” path
  • CSS Blocks module resolution algorithm
    • Relative Block import path resolution
    • Absolute Block import path resolution
    • node_module Block import path resolution

Detailed design

Rename @block-reference to @block

After some time out in the wild, we’ve received feedback that typing @block-reference is onerous and looks weird.

This proposal would update @block-reference:

@block-reference foobar from "path/to/file.block.css";

To @block:

@block foobar from "path/to/file.block.css";

This has the added benefit of providing the option of backwards compatibility / deprecation for this feature change, although we are pre-1.0 and this is not required.

@block Imports

To enable a more robust module delivery system in css-blocks, this proposal would define the API options for @block as follows.

Token Definition
<block-import> ::= " @block " <blocks-list> " from " <block-path>
<blocks-list> ::= <default-block> | <named-blocks> | <default-block> " , " <named-blocks>
<default-block> ::= <ident>
<named-blocks> ::= " ( " <named-ref> { " , " <named-ref> } " ) "
<named-ref> ::= <local-name> | <aliased-block>
<aliased-block> ::= <ident> " as " <local-name>
<local-name> ::= <ident> (Note: Lexer restriction – cannot be “default”)
<block-path> ::= "<any-value>" ’ | " " <any-value> " "

Examples of this grammars use are

Default @block imports from a Block module

@block local-name from "path/to/block.css";

In the above example, the default exported block from the block file discovered at <block-path> will be available under the local name local-name.

Named @block imports from a Block module

To import a named export of a Block file:

/* Direct named import */
@block ( other-block ) from "path/to/block.css";

/* Aliased named import */
@block ( other-block as local-name ) from "path/to/block.css";

/* Alternate default block import – the following two lines are equivalent! */
@block ( default as local-name ) from "path/to/block.css";
@block local-name from "path/to/block.css";

/* Multiple named imports */
@block ( 
  other-block-1 as local-name, 
  other-block-2, 
  other-block-3 as local-name-2 
) from "path/to/block.css";

/* Multiple named imports with default import */
@block other-block, ( 
  other-block-1 as local-name, 
  other-block-2, 
  other-block-3 as local-name-2 
) from "path/to/block.css";

@block Exports

Default Block exports from a module

All rules defined in the scope of a Block file are the default export of a block. So, the following file exposes a single block called default which contains the BlockClasses :scope and .foo when imported elsewhere:

:scope { color: red; }
.foo { color: blue; }

Even if there are no declarations in a Block file, there will always be a default block exported.

Named Block exports from a module

Any imported Blocks that need to be made available from the Block file as named exports must be explicitly re-exported. A similar syntax to @block imports is used.

/* Named Export */
@export block-name;

/* Multiple Named Export */
@export ( block-name-1, block-name-2 );

/* Aliased Export */
@export ( block-name as aliased-name );

/* Block Redirects */
@export block-name, (other-block as aliased-name) from "path/to/a.block.css";

default as a reserved word

To avoid naming conflicts and import/export ambiguity, user will be unable to import or export blocks under the local name default. If this were allowed, it would become ambiguous how the imported default block would interact with the local Block definition, also called default. The following would throw a build time error of “Error: ‘default’ is a reserved word.”:

/* Error: Can not import "block-1" as reserved word "default". */
@block ( block-1 as default ) from "block-1.block.css";

/* Error: Default Block from "block-1.block.css" must be aliased to a unique local identifier. */
@block ( default ) from "block-1.block.css";

/* Error: Can not export "block-1" as reserved word "default". */
@export ( block-1 as default ) from "block-1.block.css";

Execution order and name conflicts

@block imports are statically defined (I mean, what else is CSS good for) and parsed in order of appearance before the default Block’s contents are parsed. Because of this, you can imagine that all @block references are hoisted at runtime and processed first, regardless of location in the file.

Local identifier values will be assigned Block references in order of execution. Duplicate identifiers will have their values overwritten.

@block ( block-1 as foo ) from "block-1.block.css";
:scope {
  extends: foo; /* Value of `foo` is `block-2b` */
}
@block ( block-2a as foo, block-2b as foo ) from "block-2.block.css";

css-blocks package.json config field

Modules that deliver Block files may choose to add an optional css-blocks: { ... } configuration field to their package.jsons. Here they may define configuration options for their module. At the time or writing, there is only one valid property for the options hash:

Key Default Definition
main ModuleRoot Custom Block module “main” path. Usage defined in the module resolution algorithm below.

CSS Blocks module resolution algorithm

Heavy inspired (aka: close to outright copied) from the Node.js Resolution Algorithm

import X from module at path Y

  1. If X is a core module, a. return the core module b. STOP
  2. If X begins with ‘/’ a. set Y to be the module root (closest package.json)
  3. If X begins with ‘./’ or ‘/’ or ‘…/’ a. LOAD_AS_FILE(Y + X) b. LOAD_AS_DIRECTORY(Y + X)
  4. LOAD_NODE_MODULES(X, dirname(Y))
  5. THROW “not found”

LOAD_AS_FILE(X)

  1. If X is a *.block.css file, load X as a Block. STOP
  2. If X.block.css is a file, load X.block.css as a Block. STOP
  3. If there is a preprocessor registered for the file’s extension, preprocess the file and load the result as a Block. STOP

LOAD_INDEX(X)

  1. If X/index.block.css is a file, load X/index.block.css as JavaScript text. STOP
  2. If there is a preprocessor registered for the index file’s extension, preprocess the file and load the result as a Block. STOP

LOAD_AS_DIRECTORY(X)

  1. If X/package.json is a file, a. Parse X/package.json, and look for “css-blocks.main” field. b. let M = X + (json main field) c. LOAD_AS_FILE(M) d. LOAD_INDEX(M)
  2. LOAD_INDEX(X)

LOAD_NODE_MODULES(X, START)

  1. let DIRS = NODE_MODULES_PATHS(START)
  2. for each DIR in DIRS: a. LOAD_AS_FILE(DIR/X) b. LOAD_AS_DIRECTORY(DIR/X)

NODE_MODULES_PATHS(START)

  1. let PARTS = path split(START)
  2. let I = count of PARTS - 1
  3. let DIRS = [GLOBAL_FOLDERS]
  4. while I >= 0, a. if PARTS[I] = “node_modules” CONTINUE b. DIR = path join(PARTS[0 … I] + “node_modules”) c. DIRS = DIRS + DIR d. let I = I - 1
  5. return DIRS

Outstanding Questions

  • Do we allow for truly private Blocks in a module? This proposal does not allow for that.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:16 (15 by maintainers)

github_iconTop GitHub Comments

1reaction
chriseppsteincommented, Sep 5, 2018

I’m fine making it an error if dev time flexibility is not a strong enough argument.

I like errors. They are clear and they keep me from doing dumb things and being confused about them. If I lose 1-2 min to scratching my head in confusion, it eats up a lot of the savings of not having to do an easy thing that only saves 5-10 seconds.

1reaction
amiller-ghcommented, Sep 5, 2018

You would have to explicitly import local-block-1 from block-1.block.css into block-2-block.css to have access to it in block-2’s scope, so in your above example:

/* block-2.block.css */
@block block-1, ( local-block-1 ) from "block-1.block.css";
/* `local-block-1` is undefined */

Instead, if you import local-block-1 from block-1.block.css:

/* block-2.block.css */
@block block-1, ( local-block-1 ) from "block-1.block.css";
/* 
  `local-block-1` is defined and set to the default export from `block-foo.css`, 
   which was re-exported by `block-1.block.css` as `local-block-1`
*/
Read more comments on GitHub >

github_iconTop Results From Across the Web

Extended Syntax - Markdown Guide
They include basic syntax and build upon it by adding additional elements like tables, code blocks, syntax highlighting, URL auto-linking, and footnotes. Many ......
Read more >
Noweb Reference Syntax (The Org Manual)
Expansion of noweb syntax references in the body of the code block when evaluating, tangling, or exporting. ... the second code block is...
Read more >
WordPress Block Reference for developers - Full Site Editing
This WordPress block reference is a quick way to find a blocks CSS class or block markup. Learn which block supports which attribute....
Read more >
Language Specification for Blocks - Clang
A Block literal expression produces a reference to a Block. It is introduced by the use of the ^ token as a unary...
Read more >
Obsidian Block References & Transclusion | Sorry Roam!
CHECK THESE OUT ◀︎▭▭▭▭▭▭▭▭▭▭📧️ NEWSLETTER: https://bryanjenkstech.ck.page/d4ec0713d5 DISCORD: https://discord.gg/MxCVshN🗣️ ...
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