Skip to content

Conversation

@1231231231231231231231231

Hi! I am new to modern web frameworks (but have some experience with vanilla/classic JS, PHP Python, you name it) and was really struggling to get this working. Thought I had tried everything, going so far as to look at jsfiddle with the element inspector to find differences between why it's working on their platform but not in my own HTML file, or trying to host it on a web server instead of accessing through the file:// protocol. Nothing. Today, I figured out the problem is that the code needs to be placed in a module script tag! The file being included explicitly says nomodule! I have no idea what this newfangled script property does yet (going to look it up later), but it's required for the example code to work.

This pull request proposes to include this necessary context in the basic example to get people started. This makes the example functional, as one can now copy-paste the code and it will simply work.

Without this, the page will say Uncaught TypeError: dom is null with a stack trace leading into the VanJS code, making me initially think your code is broken. (The minified code, even less helpfully, says e is null.)

An alternative, if you prefer, might be to mention in the page text that type=module is needed

@1231231231231231231231231
Copy link
Author

I just noticed that the preview Getting Started page looks no different and still uses the old code rather than including my change. Did I do something wrong?

@Tao-VanJS
Copy link
Member

Hi @1231231231231231231231231,

Thanks for reaching out!

I believe the code in "Test It Out" section can work regardless of whether you're using <script type="module"> or not. For instance, the jsfiddle version linked from the web page is using the nomodule version (thus it's using <script> rather than <script type="module">). If you're encountering problems, it's probably due to other reasons.

@1231231231231231231231231
Copy link
Author

Huh, that's interesting. Does the following code work for you then, if you put it in a file like test.html and then open that in a browser, either via file:///path/to/test.html or on something like http://localhost/test.html?

<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/vanjs-org/van/public/van-1.5.2.nomodule.min.js"></script>
<script>
const {button, div, pre} = van.tags

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))

const Run = ({sleepMs}) => {
  const steps = van.state(0)
  ;(async () => { for (; steps.val < 40; ++steps.val) await sleep(sleepMs) })()
  return pre(() => `${" ".repeat(40 - steps.val)}🚐💨Hello VanJS!${"_".repeat(steps.val)}`)
}

const Hello = () => {
  const dom = div()
  return div(
    dom,
    button({onclick: () => van.add(dom, Run({sleepMs: 2000}))}, "Hello 🐌"),
    button({onclick: () => van.add(dom, Run({sleepMs: 500}))}, "Hello 🐢"),
    button({onclick: () => van.add(dom, Run({sleepMs: 100}))}, "Hello 🚶‍♂️"),
    button({onclick: () => van.add(dom, Run({sleepMs: 10}))}, "Hello 🏎️"),
    button({onclick: () => van.add(dom, Run({sleepMs: 2}))}, "Hello 🚀"),
  )
}

van.add(document.body, Hello())
</script>

For me, in Firefox, this throws the aforementioned exception in the console while showing a blank webpage. Adding type=module in the second line makes it work

@Tao-VanJS
Copy link
Member

Hi @1231231231231231231231231,

I think you need to enclose everything with <body></body>.

@1231231231231231231231231
Copy link
Author

Oh, yes indeed, that also fixes it! Interesting observation. I see the head is not good enough; it really needs to be the body. Using window.onload or setTimeout also work, so it seems to depend on something being loaded that isn't yet there when one invokes the code from the root or head elements.

Should it be documented, then, that the library depends on the DOM being... built up, or whatever is happening exactly?

We could include the <body> tags but that isn't very pasteable when one wants to drop it into an existing page, so more appropriate is probably to bind to the window load event?

@Tao-VanJS
Copy link
Member

For module inline scripts, you can put it anywhere in the HTML page. But for non-module inline scripts, you need to put the script inside the <body> tag. This is due to the execution order of JavaScript code. i.e.: module inline scripts are executed after the document is parsed, but non-module inline scripts are executed as soon as encountered (unless you add defer attribute).

I understand this might be confusing to newcomers but I don't feel VanJS website should include these nuances (there are just too many in the web standard to include).

@1231231231231231231231231
Copy link
Author

Am I really a newcomer after writing web applications with JS for over 15 years? Or do I just have trouble with learning at that point! 😆

Yes, web standards education is beyond the scope of VanJS, but the first Getting Started example does not work when someone copies it as-is

Many JS examples depend on other elements, like when you do <div id=output></div><script>document.querySelector("#output").innerHTML=...;</script>, but in those cases it's obvious (at least if you're not super new to JS/HTML) that it requires the output element to exist and so the order matters. Here, no HTML is given and no custom elements are being referred to, so I did not realize it does actually depend on some HTML structure existing. Perhaps I'm the only person who will ever run into this, though

What if the code would use document.firstChild instead of document.body? I just tried and that always works; there is always a usable element in the document, just not always the body. This solution wouldn't add any lines to the example code, it just changes one variable name to something that universally works. Do you think that's a good solution to the conundrum?

@1231231231231231231231231
Copy link
Author

Maybe I should add: for me it doesn't matter, I know the solution now so feel free to decline. I can start using VanJS and learn about more modern frameworks as I wanted to. I'm just proposing a solution for those who come after me :)

@Tao-VanJS
Copy link
Member

Hi @1231231231231231231231231,

I appreciate your feedback. The code example in "Getting Started" page is intended to work in both module-typed scripts and non-module-typed scripts. Unfortunately the requirements of script placement for module-typed scripts and non-module-typed scripts are subtly different. I'm afraid there isn't a very brief way to describe the requirements for both. This is just one type of nuances of web standard. Another relevant nuance is module-typed scripts only work when the HTML is hosted by HTTP servers, but don't work if you simply open static HTML files.

At the end of the day we need to set a boundary. While I understand this kind of nuances are confusing to some people if they're not aware of them, I don't think VanJS website is the place to include all of them.

Regarding your suggestion of using document.firstChild instead of document.body, please note that document.firstChild will get you the entire <html> of the page instead of the <body> part. Thus this is probably not what we typically want.

but the first Getting Started example does not work when someone copies it as-is

This is technically true. The code example listed in "Getting Started" page is in JavaScript, and you can't open JavaScript file directly in the browser to run it. You have to place the JavaScript code somewhere in an HTML file, one way or another. And the requirements of the placement are different between module-typed scripts and non-module-typed scripts, and can't be explained very briefly. I think the best course of action for me is to provide a link to our current discussion in "Getting Started" page for people who are struggling to make their scripts to work, which I will do shortly.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants