Loading scripts on your webpage
Tags: html, javascript
Published: 2018-11-08 02:11:29

---
title: Loading scripts on your webpage
published: true
description: Let's talk about something simple, loading scripts on a webpage.
tags: html, javascript
cover_image: https://thepracticaldev.s3.amazonaws.com/i/pk3ebhr13cm98z59h55h.png
---

I missed my train and have a hour to fill so let's talk about something simple, loading scripts on a webpage.

## As a bundle
A super easy way to enforce all your scripts being loaded is to bundle them all into one single file. This however is expensive (stupid) because you can not import only the ones you need this way.

## As scripts document _<head>_
As little ducklings we were taught to place scripts in the document _head_ as they are loaded first thing immediately when loading the webpage.

```html
<html>
    <head>
        <title></title>
        <script src="main.js"></script>
        <script src="util.js"></script>
        <script src="events.js"></script>
        <script src="speech.js"></script>
    </head>
    <body>
    <h1>Page Title</h1>
    </body>
</html>
```

A script element inside the document _head_ can not access HTML elements declared after the script because when the script is being loaded, the target element does not exist yet. In other words, in the above example you can not access the _h1_ element from _main.js_. This is why often ducklings want their scripts to be loaded after the rest of the page already has.

## As scripts at end of _body_
If you want to execute your scripts after the document has loaded then simply put them at the end of your body. 
It became common practice at some point to do this because it would speed up loading of your page.  What they mean by this is that the page images and stylesheets will already have been loaded. The script tags do not block/delay them. This is much better for the user.

```html
<html>
    <head>
        <title></title>
    </head>
    <body>
    <h1>Page Title</h1>
    <script src="main.js"></script>
    <script src="util.js"></script>
    <script src="events.js"></script>
    <script src="speech.js"></script>
    </body>
</html>
```

It is very possible to access elements on the page from scripts declared in the page _head_ but you have to wait for an event that tells you the page has loaded. In the old days one assigned an _onload attribute_ to the page body. 
```html
<body onload="method()"></body>
``` 

## Using jQuery 
Everybody knows the following.
```js
$(document).ready(function() {
  // the page has finished loading
}
```

## Vanilla
This is _almost_ the same as above but without jQuery.

```js
document.addEventListener('DOMContentLoaded', event => {
  // the page has finished loading
})
``` 

## Injecting them programmatically
You can imitate some sort of require function by _injecting scripts into your head_. This really not as scary as it sounds.

```js
function importScript(src) {
    let script = document.createElement('script')
    script.setAttribute('src', src)
    document.head.appendChild(script)
}

importScript('main.js')
importScript('util.js')
importScript('events.js')
importScript('speech.js')
```

## With async function
Some people insist on wrapping mutliple promises into an asynchronous function.

```js
// imagine the same import function but one that implements a Promise.
document.addEventListener('DOMContentLoaded', async event => {
  window.main = await importScript('main.js')
  window.util= await importScript('util.js')
  window.events= await importScript('events.js')
  window.speech = await importScript('speech.js')
}
```

## As modules
It is now 2018, the ducklings have become swans and we can [import modules](https://developer.mozilla.org/nl/docs/Web/JavaScript/Reference/Statements/export) using an extra attribute in our script tags. The functional programmers are bent on this and they are probably the reason it is spreading to Node.

```html
<script type="module">
  import * as util from './util.js'
  util.default()
  util.extra()
</script>
``` 
```html
<script type="module">
  import { display, extra } from './main.js' // that too
  display.message()
  extra()
</script>
``` 
> A friend of mine asked why Node doesn't _simply use export_. This is because Node was there a lot earlier than when the export keyword was introduced. :P

The import keyword used as a function enables [dynamic imports](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#Dynamic_Import). It returns a Promise that resolves whatever the script exports. Using import like this *does not require* the _type="module"_ attribute of your script tag.

```js
import('./util').then(module => window.util = module).catch(console.error)
```

Because import makes [promises](https://developer.mozilla.org/nl/docs/Web/JavaScript/Reference/Global_Objects/Promise), we can await it in the [DOMContentLoaded](https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded) event as long as our event handler function is async.

```js
document.addEventListener('DOMContentLoaded', async event => {
    window.util = await import('./util')
})
```
To load multiple scripts, simply iterate an Array

For some reason you might want a resolver function to import scripts by identifier (not full path) and why not a context object that in this case defaults to window. What you see below is not ideal but you get the point.

```js
let libs = ['main', 'utils', 'session']
const init = async (context = window) => libs.forEach(async lib => context[lib] = await import(init.resolve(lib)))
init.resolve = lib => `./js/${lib}.js`


init(window) // libs are now properties of window
init({}) // initialize on empty object
init({
    utils: 'abc'
}) // utils is overwritten
```

## Using [RequireJS](https://requirejs.org/docs/start.html)
Personally I never understood why anyone would think that this is what they need in life. It never solved any problems for me. However because of its reputation it needs to be included.

```js
requirejs(["util"], util => {
    //This function is called when util.js is loaded.
    window.util = util
})
```

## Acquire
A [simplification](https://github.com/jochemstoel/acquire/blob/master/acquire.js) of _requirejs_ that evaluates the responseText of a XMLHttpRequest in its own context that contains a module identifier. There was no [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) at the time. There were no module scripts or import/export keywords. Acquire supports both synchronous and asynchronous with a single function call but a synchronous XMLHttpRequest is perhaps the most deprecated thing you can do period.

> If you liked this article then come back here more often on dev.to