module
https://www.yuque.com/qinsjs/jsinfo/ifmpz2
一个模块(module)就是一个 .js 文件
对于浏览器,必须使用 <script type="module"> 特性(attribute)来告诉浏览器,此脚本应该被当作模块(module)来对待。
Module 只通过 HTTP(s) 工作!!
一些核心知识
- 模块始终默认使用 use strict
- 顶级作用域(top-level scope)。即 变量只在本文件可见。
- 只有第一次导入被解析,后面无论 import 多少次,都是一样的。
- 模块中的 this 是 undefined
import.meta
import.meta 对象包含关于当前模块的信息。
export
js
export 任意声明js
export function (){}
export class Anmin{}函数 和 类 的声明后不需要使用分号!这是个大家都在用的规范。
导出与声明分开
即:
js
const a = 1;
const b = () => console.log("hello");
export { a, b };import
js
// 此方式更好,建议使用这种方式
import { a, b } from "./xxx.js";也可以导入为一个对象
js
import * as x3 from "./xxx.js";
console.log(x3.a);as
import 和 export 都可以 as
js
import { sayHi as hi, sayBye as bye } from "./say.js";js
export { sayHi as hi, sayBye as bye };default
“一个模块只做一件事”
export
每个文件应该只有一个 export default
因为只有一个,所以可以没有名字:
js
// 没有类名
export default class { }
// 没有函数名
export default function( ) { }
export default 1;
export default ['Jan', 'Feb', 'Mar','Apr', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];也可以主动 default:
js
function sayHi(user) {
alert(`Hello, ${user}!`);
}
export { sayHi as default };import
js
export default class User {}
export function sayHi(user) {}这两种方式都是可以的
js
import { default as User, sayHi } from "./user.js";js
import * as user from "./user.js";
let User = user.default; // 默认的导出重新导出
export ... from ...动态导入
加载模块并返回一个 promise。
import() 并不是函数,不要使用 call/apply!
script type="module",import() 也可以工作
示例:
js
export const config = {};
export default 1;js
import("./config.js").then(console.log);
// {
// config:(...),
// default:(...),
// Symbol(Symbol.toStringTag): "Module"
// }浏览器特定功能
todo
“bare” module
严格来说,module 不支持裸模块(bare module)。必须是 URL(相对 或 绝对)
但是 Node.js 和 打包工具 有自己的路径处理方式,所以他们可以使用。
“nomodule”
js
<script type="module">
// 现在浏览器会执行这里
</script>
<script nomodule>
// 现在浏览器 知道 module 和 nomodule , 所以会跳过 nomodule
// 老浏览器并不知道,所以老浏览器会执行这里。
// 老浏览器也会 ignore module
</script>Demo:静态 http 服务
pnpm add koa mime-types
文件放在 html 目录下
js
const path = require("path");
const fs = require("node:fs/promises");
const { createReadStream } = require("fs");
const Koa = require("koa");
const app = new Koa();
const mime = require("mime-types");
const l = console.log;
app.use(async (ctx) => {
const dir = path.join(__dirname, "/html", path.dirname(ctx.path));
let dirStat;
try {
dirStat = await fs.stat(dir);
} catch (error) {}
if (!dirStat?.isDirectory()) {
l("无效路径 > ", dir);
ctx.status = 404;
ctx.body = "404 找不到对应的资源";
return;
}
let fileStat;
const name = path.basename(ctx.path);
const ext = path.extname(ctx.path);
const getFileName = function () {
if (!name) return "index.html";
if (ext) {
return name;
} else {
return path.join(name, ".html");
}
};
const fileName = getFileName();
try {
fileStat = await fs.stat(path.join(dir, fileName));
} catch (error) {}
if (!fileStat) {
l("没有对应文件 > ", dir, name, ext);
ctx.status = 404;
ctx.body = "404 没有对应资源文件";
return;
}
ctx.set("content-type", mime.lookup(fileName));
ctx.body = createReadStream(path.join(dir, fileName), { encoding: "utf8" });
});
app.listen(3000);