Re: [WICG/webcomponents] HTML Modules (#645)

Anyone played with some of these ideas in real life?

I come with some good engagement with the usecase and I can say that what the warfront is dictating is a **HTML-primary**, **JS-secodnary** type of a module system. It seems to me that the JS approach is all being induced for some reason I can't figure out! It seems to me that important comments here emphasizing a HTML-oriented approach aren't being honoured at all. But truth is, these comments are simply the usecase talking. Even with the passing of time, the usecase today is still all about just being able to reuse HTML all by itself.

Unfortunately, JavaScript keeps hunting down HTML everywhere. **It's a feeling we don't want!** And if we end up shipping one more thing like this, we would naturally seek *peace* with some other means to the same end, and "HTML Modules" would sit all by itself!

All I have ever wanted, is being able to reuse HTML content; and without JavaScript! I already have ES6 modules for anything JS! Let me explain properly...

1. **Should HTML modules be JavaScript oriented (using ES6's module infrastructure) or HTML oriented (using HTML's own infrasture)?**
    
    The answer should be obvious when we understand that we are talking about two different domains that each lends itself to be treated differently, with each having its own concept of reusability.
    
    + When we think of HTML modules, what we are really thinking of is *reusable HTML contents - not reusable JavaScript*, as this is what ES6 modules are designed for. And when we look, it is for this purpose of reusability in HTML that we have the `<template>` element. And with the `template.content` API, JavaScript code is already able to *import* these reusable HTML elements for use.
    
        So, is there anything new about reusing HTML contents that we want to drop HTML's perfect infrastructure for the job in favour of ES6 modules? Is it just about that HTML now being in a remote file? We could simply do something that gets these remote contents to the same end - the `<template>` element!

        ```html
        <template src="/bundle.html"></template>
        ```
        
        The template element above is simply loading itself from a remote file. This is even how HTML thinks.

        ```html
        <script>
            // Code
        </script>

        or 

        <script src="/script.js"></script>
        ```
    
        ```html
        <style>
            /* Rules */
        </style>

        or 

        <link href="/styles.css" />
        ```
    
        ```html
        <svg>
            <!-- Contents -->
        </svg>

        or

        <img src="/image.svg" />
        ```

        So, HTML already gives us a way to either define things in-place or load them from a file. I am only wondering how come the `<template>` element shipped without an equivalent feature in the first place.
        
        If *reusable HTML* is the question anywhere, it seems pretty straight forward to just ask the `<template>` element. There shouldn't be one system for consuming HTML defined statcally and another separate system for consuming the same HTML defined in a remote file. The word "load" should simply be a means to get the supposed contents to the same end. Othereise, we would be introducing a new sort of engineering for an existing concept without any additional benefit.
        
2. **How about we rather talk about spicing up reusability in HTML with the `<template>` element, this time, using the *module*, *import* and *export* paradigm, while maintaining all the benefits of doing HTML with HTML?**

    I've engaged with this concept extensively using a polyfill I made. And after a million iterations building a real-word app with it, here are my conclusions.
    
    1. The `<template>` element is just perfect as **one interface for anything reusable**, whether defined statcally or defined remotely. *And this is the HTML module! Its contents should simply be taken as exports!*

        In this sense of a module:

        1. The `<template>` element would have a `name` that's used as the *module ID*.
            
            ```html
            <template name="module1">
                <!-- Contents -->
            </template>

            or 

            <template name="module1" src="/bundle.html"></template>
            ```

        2. The *export* terminology of a standard module system would go to an `<export>` element that properly puts contents up for consumption using some *export ID*.
        
            ```html
            <template name="module1">

                <export name="export1">
                    <div>Part of export1</div>
                    <div>Part of export1</div>
                </export>

            </template>
            ```

            Contents may also be tagged to an export ID using something like an `exportgroup` attribute.

            ```html
            <template name="module1">

                <div exportgroup="export1">Part of export1</div>
                <div exportgroup="export1">Part of export1</div>

            </template>
            ```

        3. The *import* terminology of a standard module system would go to an `<import>` element that let's us declaratively place any of a module's *export* on any location in the main document.
        
            ```html
            <body>
                <import name="export1" template="module1"></import>
            </body>
            ```

            > Conincidentally, this *import* (or *include*) feature is something we've all asked for under different proposals. What's new here is that instead of being all about including server-side contents, the `<import>` element just maintains a relationship with the `<template>` element - the module. So, whether a `<template>` has its *content* statically defined or has it loaded, the `<import>` element's job would be just to *import* from the `<template>`.
    
    2. Many new things become possible with this *HTML-oriented* HTML module system, all of which would be lost otherwise.
        
        1. Modules would now be nestable, to let us organize them more meaningfully.
        
            ```html
            <template name="module1">

                <div exportgroup="export1">Part of export1</div>
                <div exportgroup="export1">Part of export1</div>

                <template name="module_nested_remote" src="/bundle.html"></template>

            </template>
            ```

            So, a module can have other modules, which themselves can have other modules, as long as they each have a module ID.
            
            The full module ID for a nested module becomes a path like `module1/module_nested_remote`.
        
        2. Loading modules from a remote file can go without any *render-blocking* or *defer* semantics. They would simply announce a successful load event whenever loading is successful - just the way the `<img>` element works. Then, `<import>` elements in the UI that depend on these remote contents are simply resolved as exports become available - just as the `<img>` element is rendered at whatever time loading is successful.
        
            ```html
            <body>
                <!-- resolves when module1/module_nested_remote loads -->
                <import name="export1" template="module1/module_nested_remote"></import>
            </body>
            ```

        3. With the event system of HTML modules, the main document/UI is able to maintain a **dynamic relationship** with its modules.
        
        Then, an HTML modules API!

        1. With something like a `document.templates` property, we could simply access modules without having to query the document for `<template>` elements using CSS selectors.

            ```js
            let module1 = document.templates.module1;
            ```

            And for nested modules, something like a `template.templates` property would be used.

            ```js
            let module_nested_remote = module1.templates.module_nested_remote;
            ```
        
        2. With something like a `template.exports` property, we could access a module's exports without having to query `<template>` elements using CSS selectors.
            
            ```js
            let import1 = module1.exports.export1;
            ```

        3. And the `document.addEventListener()` method could always be used to observe the state of a document's modules - especially where modules are loading remote content or where modules are being programmatically added to the document.

        Then some extended usecases where some exports have some JS?

        ```html
        <template name="module1">

            <export name="export1">
                <div>Part of export1</div>
            </export>

            <export name="export1">
                <div>
                    Part of export2
                    <script>
                        // Some JS?
                    </script>
                </div>
            </export>


        </template>
        ```

        Ususally, this kind of JS is solely for the purpose of **scoped functionality**, not for the purpose of being imported into another script. If I really wanted to import a script from another script, I would do so directly:

        ```js
        import something from './script.js';
        ```

        It doesn't make sense to me that I would first have taken the script into some HTML, then begin debating *how to import the script*!

        **Scoped JavaScript** is an interesting possibility that should really be explored for its peculiar usecases. This, I certainly have! And here's what I've settled for:

        ```html
        <template name="module1">

            <export name="export1">
                <div>Part of export1</div>
            </export>

            <export name="export2">
                <div id="some-div">
                    Part of export2
                    <script type="subscript">
                        // The this variable is a reference to the immediate host element
                        console.log(this.id); // some-div
                    </script>
                </div>
            </export>

        </template>
        ```

        And the script remains inert until the export is imported into the main document. It ever runs in the context of its immediate host element. Variables defined within aren't available outside, but variables in the global scope are available inside.

        On being imported, our final document becomes:

        ```html
        <body>
            <!-- <import name="export2" template="module1"></import> -->
            <div id="some-div">
                Part of export2
                <script type="subscript">
                    // The this variable is a reference to the immediate host element
                    console.log(this.id); // some-div
                </script>
            </div>
        </body>
        ```
        
        And the rest of the world of scoped functionality can go on:

        ```html
        <body>
            <!-- <import name="export2" template="module1"></import> -->
            <div id="some-div">
                Part of export2
                <script type="subscript">
                    console.log(this.closest('body')); // <body>
                    console.log(document.title); // ...
                    this.addEventListener('click', () => {
                        this.remove();
                    });
                </script>
            </div>
        </body>
        ```

I can say convincingly that once you begin working with `<template>`s, `<import`s, and `<script type="subscript">`, everything becomes simple. We've particularly taken an app to production at WebQit with this approach, using the polyfill linked below.

You'll find out however that all of the above features is only a part of what we need together to be able to author modular, reactive UI with just native HTML. Answering this challenge has been my project at WebQit which I have summed up as OOHTML (formally CHTML). OOHTML (Object-Oriented HTML) is **a proposed suite** of UI features that let's us build modular, reactive UIs natively.

+ Please [see the proposal at the WICG](https://discourse.wicg.io/t/proposal-chtml/4716). (Discussion mainly at the WICG.)
+ And [here is the project - the polyfill - on Github](https://github.com/webqit/oohtml). (The polyfill has full support for all OOHTML's features and its already being tested in production.)
+ And [here is the documentation](https://webqit.io/tooling/oohtml) (progressively being improved on.)


-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/WICG/webcomponents/issues/645#issuecomment-766796605

Received on Monday, 25 January 2021 12:56:45 UTC