shinsenter / defer.js

🥇 A lightweight JavaScript library that helps you lazy load (almost) anything. Defer.js is dependency-free, highly efficient, and optimized for Web Vitals.
https://shinsenter.github.io/defer.js/
MIT License
277 stars 45 forks source link

question(defer): defer Mermaid #111

Closed Kristinita closed 2 years ago

Kristinita commented 2 years ago

1. Summary

I failed to use Defer.js with Mermaid.js — JavaScript diagramming and charting tool.

It would be nice, if you tell me how to use Defer.js for Mermaid.

2. Mermaid MCVE

2.1. Sources

Sources for the simple Mermaid pie chart on Repl.it.

  1. index.html:

    <!doctype html>
    <html lang="en">
        <head>
            <meta charset="utf-8">
            <meta name="viewport" content="width=device-width, initial-scale=1">
            <title>Kira Mermaid MCVE</title>
            <script src="https://cdn.jsdelivr.net/npm/@shinsenter/defer.js/dist/defer_plus.min.js"></script>
            <script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js" defer></script>
            <script src="mermaid.js" defer></script>
        </head>
        <body>
            <pre class="mermaid">
            pie showData
                title Who is Kira?
                "Goddess": 1
            </pre>
        </body>
    </html>
    
  2. mermaid.js:

    mermaid.initialize({ startOnLoad: true });
    

2.2. Result

Demonstration on Repl.it:

Kira Goddess pie chart on Mermaid

I can’t get the same result with Defer.js.

3. Not helped

I read Mermaid API usage and tried variants below. None helped me.

3.1. 2 Defer.js() functions

Defer.js('https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js', 'mermaid', 1000);
Defer.js('mermaid.js', 'mermaid-local', 2000);

3.2. Defer.all()

<script type="kiramermaid" src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
<script type="kiramermaid" src="mermaid.js"></script>

<script>
    Defer.all('script[type="kiramermaid"]', 1000);
</script>

3.3. mermaid.initialize()

Defer.js('https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js', 'mermaid', 1000, function()
    { mermaid.initialize({ startOnLoad: true });});

3.4. mermaid.initialize() without options

Defer.js('https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js', 'mermaid', 1000, function()
    { mermaid.initialize({});});

3.5. mermaid.init()

Defer.js('https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js', 'mermaid', 1000, function()
    { mermaid.init({});});

3.6. mermaid.initialize() after DOMContentLoaded event

Defer.js('https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js', 'mermaid', 1000, function()
    { document.addEventListener('DOMContentLoaded', _ => new mermaid.initialize({ startOnLoad: true }));});

3.7. mermaid.init() after DOMContentLoaded event

Defer.js('https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js', 'mermaid', 1000, function()
    { document.addEventListener('DOMContentLoaded', _ => new mermaid.init());});

Thanks.

shinsenter commented 2 years ago

Hey @Kristinita

Thank you for your question, and I would like to answer your question.

After going through the source code of Mermaid.js, I think that initializing Mermaid.js after lazy loading it just doesn't work.

As they also mention on the official documentation page, it says:

By default, mermaid.init will be called when the document is ready, finding all elements with class="mermaid".

So, that means after lazy loading the Mermaid.js library (meaning you load it after the web page has finished loading), you need to manually initialize Mermaid.

You can view the source code for the mermaid.initialize here, and I found it is used to set the options for the library.

Besides, the actual function used to initialize Mermaid.js is mermaid.init, you can check the source code here, and the documentation about it here.

Therefore, your lazy loading methods from 3.1 to 3.7 (excepts 3.5) will not work if you use the mermaid.initialize function (because the mermaid.init function is not called).

About your setups

3.1. 2 Defer.js() functions

Scripts lazy loaded usign the Defer.js are asynchronous, the order of executions is not guaranteed, we cannot conclude that the Mermaid library is presented when the mermaid.min.js executed.

3.2. Defer.all()

In this case, the order of executions is guaranteed, but the mermaid.initialize does not init the library.

3.3. mermaid.initialize()

The mermaid.initialize does not init the library.

3.4. mermaid.initialize() without options

The mermaid.initialize does not init the library.

3.5. mermaid.init()

I have no idea why it didn't work. Can I have your full setup? I made one here, and it actually worked: https://jsfiddle.net/nodmtpbf/

3.6. mermaid.initialize() after DOMContentLoaded event

The DOMContentLoaded event has already been triggered before the script is dowloaded, so the callback function will not be called.

3.7. mermaid.init() after DOMContentLoaded event

The DOMContentLoaded event has already been triggered before the script is dowloaded, so the callback function will not be called.

Working setup

https://jsfiddle.net/nodmtpbf/

<script src="https://cdn.jsdelivr.net/npm/@shinsenter/defer.js@3.1.0/dist/defer_plus.min.js"></script>
<script>
    Defer.js('https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js', 'mermaid', 0, function() {
        mermaid.init();
    });
</script>
Kristinita commented 2 years ago

Status: CONFIRMED :heavy_check_mark:

Your setup works for me for MCVE and real Mermaid charts.

It looks like I made a mistake by adding {braces}:

+ mermaid.init();
- mermaid.init({});

(And I don’t think 2 different functions with names mermaid.init() and mermaid.initialize() is the best practice.)

Sorry for taking your time.

Thanks.

shinsenter commented 2 years ago

@Kristinita Good to see your problem solved. Have a nice day!

If you find this library helpful, please give me a star on Github or consider supporting me so I can continue to create other open source projects.