iife
title: IIFE authors: [huakun] tags: [Web]
https://developer.mozilla.org/en-US/docs/Glossary/IIFE
An IIFE (Immediately Invoked Function Expression) is a JavaScript function that runs as soon as it is defined.
Immediately Invoked Function Expression (IIFE) 是 JavaScript 中的一种常见的设计模式,它是一个立即执行的匿名函数表达式。IIFE 通常用于创建一个独立的作用域,避免变量污染全局作用域。
(function () {
// …
})();
(() => {
// …
})();
(async () => {
// …
})();
IIFE is usually used to create a separate scope to avoid polluting the global scope. In this blog I will instead talk about the use of IIFE in hosting web pages.
Traditionally, static websites are compiled into an index.html
file as an entrypoint. css and js files are linked in the head
and body
tags.
Here is an example of a simple index.html
file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + Vue + TS</title>
<script type="module" crossorigin src="/assets/index-D7F47PqG.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DRBiz0Jz.css" />
</head>
<body>
<div id="app"></div>
</body>
</html>
You can see that in such a client-side rendered web page, the HTML file doesn't contain any content. The content is rendered by the JavaScript file linked in the head
tag.
The index.html
is only used as a container for the JavaScript file. The JavaScript file is responsible for rendering the content of the web page.
Theoretically, we can ship a single JavaScript file contains all the logic and content of the web page (including styles and images (png doesn't work, but svg does)).;
Vite Config
For example, this is the original vite.config.ts
file for a vue project:
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
});
Output dist
folder:
dist
├── assets
│ ├── Vue.js_Logo_2.svg-BtIZHRhy.png
│ ├── index-CjgLCVzZ.css
│ └── index-CwnRthTM.js
├── index.html
└── vite.svg
Next, set output format to iife
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import path from "path";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
build: {
emptyOutDir: false,
rollupOptions: {
input: path.resolve(__dirname, "./src/main.ts"),
output: {
format: "iife",
dir: path.resolve(__dirname, "./dist"),
entryFileNames: "web.js",
},
},
},
});
dist
├── assets
│ └── Vue.js_Logo_2.svg-BtIZHRhy.png
├── vite.svg
└── web.js
Now how to use the web.js
without an index.html
file?
Let's serve the dist
folder with a simple http server:
serve dist --cors
The web.js
is at http://localhost:3000/web.js
In an HTML file,
<!DOCTYPE html>
<html lang="en">
<body>
<iframe></iframe>
<script>
fetch("http://localhost:3000/web.js", {
method: "GET",
})
.then((res) => res.text())
.then((data) => {
document
.querySelector("iframe")
.contentDocument.write(
"<div id='app'/><script>".concat(data, "<\/script>")
);
});
</script>
</body>
</html>
Here we are rendering the content of web.js
in an iframe
. It can also render the page directly as long as there is a <div id="app" />
.
<!DOCTYPE html>
<html lang="en">
<body>
<script>
fetch("http://localhost:3000/web.js", {
method: "GET",
})
.then((res) => res.text())
.then((data) => {
document.write(
"<div id='app'></div><script>".concat(data, "<\/script>")
);
});
</script>
</body>
</html>
This is because the main.ts
is like this
import { createApp } from "vue";
import "./style.css";
import App from "./App.vue";
createApp(App).mount("#app");
So what can be the use case of this?
- The key benefit is that the website content doesn't have be to hosted on a server. It can be saved in a database and fetched by the client like a function.