blog

ESモジュール - ブラウザネイティブモジュールのサポート

プリアンブルはもともとWebページで単純なスクリプト機能を実行するために設計されましたが、歴史の流れは、複雑で大規模なアプリケーションを書くために、アプリケーションを個別にインポートできるモジュールに...

Sep 3, 2020 · 7 min. read
シェア

はじめに

JavaScriptは、もともとWebページで単純なスクリプト機能を実行するためにのみ使用されていましたが、歴史の流れは、JavaScriptをより大きなステージに押し上げ、複雑な大規模アプリケーションを記述するには、JavaScriptのプログラムを個別にインポートできるモジュールに分割できるメカニズムが必要であり、Node.jsは、この目的のためにCommonJSを提供し、CommonJSはまだ欠点を持っているにもかかわらず、欠点は弱点をカバーし、Node.jsのサーバーサイドの開発では、それはまだ輝いています。たとえCommonJSはまだ欠点を持っていますが、欠点は、Node.jsのサーバーサイドの開発では、カバーアップしない、それはまだ輝いているが、残念ながら、クライアントでは、適切なモジュール機能の誕生されていない、開発者は、CMDとAMDの仕様を策定し、sea.jsとrequire.jsの2つの仕様の実装を作成する独自の創意に依存していますが、クラスライブラリは、常にクラスライブラリされている、完璧な解決策ではありません。しかし、クラスライブラリは常にクラスライブラリであり、完璧な解決策ではありません。 複数の仕様が共存する現象に直面した開発者は、フロントエンドとバックエンドの両方に共通のモジュールのメカニズムが存在することを切実に望み、最終的にブラウザはネイティブでモジュール機能を提供し、JavaScriptをより完全なものにしました。

モジュールキーワード

初心者のために、多くのオンライン教科書や教材はまだCommonJSモジュール機構を使用しています!

CommonJS

//  
// a.js つのモジュールだけをエクスポートする必要があると仮定する
module.exports = function a() { 
 // do something 
}
const a = require('./a.js')
// b.js 複数のモジュールをエクスポートする必要があると仮定する
exports.a = function a () { 
 // do something 
}
exports.b = function b () { 
 // do something 
} 
...
//  
const {a, b} = require('./b.js')

初心者の間で最も一般的な混乱は、module.exportsとexportsの関係です。exportsは、モジュール出力をパッケージ化するときにNode.jsによって提供される追加変数で、基本的にvar exports = module.exports

しかし、より大きな混乱を伴う、なぜ輸出モジュールの方法は、オブジェクトの属性の方法ではなく、直接割り当ての輸出にエクスポートすることです、この問題を明確にするための鍵は、変数の割り当ての動作の意味を理解することである、強固な基盤を持つJS開発者は、それが見つけるのは簡単ですが、このアプローチは、このように最終的なモジュールでは、Node.jsのプリセットのロジックから逸脱し、変数を書き換えます。最終的なモジュールをエクスポートすると、エラーが発生します。

ESMudule

//  
// c.js つのモジュールだけをエクスポートする必要があると仮定する
export default function c () { 
 // do something 
}
//   
import customName from "./c.js"
// d.js 複数のモジュールをエクスポートする必要があると仮定する
export function d () {
 // do something 
}
export function e () {
 // do something 
}
//   
// 導入前に正確な関数名を知る
import {d,e} from "./d.js" 
//   * いいえ。
import * as m from "./d.js"

モジュールが export default を使ってエクスポートされている場合、開発者はモジュールを参照する際にモジュール名をカスタマイズすることができます。一方、export 経由でエクスポートされたモジュールの場合、関数を導入するために正確な関数名を知っておく必要があり、ある程度面倒ですが、moduleName として * を使うことで、エクスポートされたすべてのモジュールの内容を1つのオブジェクトにまとめることも可能です。を一つのオブジェクトにまとめて返すこともできます。

区別

ESmoduleのエクスポートの動作は少し変わっていて、CommonJSのものよりずっとクリーンでパフォーマンスも高いことがわかります。

CommonJSは、requireキーワードで参照されているモジュールを見つけると、モジュールコード全体を実行し、値をフェッチしてキャッシュし、それ以降は、キャッシュから値をフェッチするだけで、1回限りの実行となり、キャッシュから値をフェッチするだけで、再度参照することを要求します。

そこで問題です:

合計10個のエクスポートされたモジュールの下にモジュールファイルがあると仮定すると、実際の開発では、参照の無駄、キャッシュに余分なコードがあるが、使用されていない、メモリ領域の無駄をもたらすモジュールの1つだけが使用されます!

ESModuleは、動的な読み取り専用参照を使用してモジュールのコードをロードするには、読み取り専用のキーワードとしてインポートし、参照の発見では、それは値を取るためにロードされたモジュールへの参照によると、スクリプトの実行段階を待って、読み取り専用の参照を生成し、これは動的な参照は、つまり、同じ使用を取ることであり、プロセスは非同期です!

非同期モジュールのロードメカニズムは非常に重要ですが、ブラウザでは、同期ロードモジュールのコストを負担することができない、一度モジュールの問題は、白い画面のページが遅くレンダリングすることはできませんにつながる、またはモジュールが大きすぎる、Webページの読み込みの遅延につながる、クライアントのユーザーエクスペリエンスの重要性では、悲惨な結果につながるでしょう!

ブラウザネイティブサポートモジュール

この記事を書いている時点で、主要なブラウザは基本的にネイティブモジュールと互換性があります。

<script type="module">では、ブラウザで直接モジュール機構を使うにはどうすればいいかというと、普通のスクリプトタグがエラーを報告する場合、ブラウザがネイティブモジュール機構を有効にすることを知らせるフラグを使うことです。

プロジェクトを作成し、注:記事のコードはMDN提供サンプル引用し、わずかに変更され、あなたがチェックするために行くことができます

プロジェクト構造カタログ

index.html
index.js
main.js
modules/
 canvas.mjs
 square.mjs

ノート

1、ネイティブモジュールの参照は、一般的にクロスドメインとして知られているJSファイルのセキュリティの制限のために、ローカルのテストを渡すことができないので、ローカルのサービスローディングページを開きます。

2、ネイティブモジュールの参照は、正しいMIMEタイプに設定する必要があります、これは非常に重要です、そうでない場合は、ブラウザが正しくモジュールをロードすることはできません、一般的なエラーとして報告されます。The server responded with a non-JavaScript MIME type

モジュールのエクスポート

// modules/canvas.js
function create(id, parent, width, height) {
 let divWrapper = document.createElement('div');
 let canvasElem = document.createElement('canvas');
 parent.appendChild(divWrapper);
 divWrapper.appendChild(canvasElem);
 divWrapper.id = id;
 canvasElem.width = width;
 canvasElem.height = height;
 let ctx = canvasElem.getContext('2d');
 return {
 ctx: ctx,
 id: id
 };
}
function createReportList(wrapperId) {
 let list = document.createElement('ul');
 list.id = wrapperId + '-reporter';
 let canvasWrapper = document.getElementById(wrapperId);
 canvasWrapper.appendChild(list);
 return list.id;
}
export { create, createReportList };
// modules/square.js
const name = 'square';
function draw(ctx, length, x, y, color) {
 ctx.fillStyle = color;
 ctx.fillRect(x, y, length, length);
 return {
 length: length,
 x: x,
 y: y,
 color: color
 };
}
function random(min, max) {
 let num = Math.floor(Math.random() * (max - min)) + min;
 return num;
}
function reportArea(length, listId) {
 let listItem = document.createElement('li');
 listItem.textContent = `${name} area is ${length * length}px squared.`
 let list = document.getElementById(listId);
 list.appendChild(listItem);
}
function reportPerimeter(length, listId) {
 let listItem = document.createElement('li');
 listItem.textContent = `${name} perimeter is ${length * 4}px.`
 let list = document.getElementById(listId);
 list.appendChild(listItem);
}
function randomSquare(ctx) {
 let color1 = random(0, 255);
 let color2 = random(0, 255);
 let color3 = random(0, 255);
 let color = `rgb(${color1},${color2},${color3})`
 ctx.fillStyle = color;
 let x = random(0, 480);
 let y = random(0, 320);
 let length = random(10, 100);
 ctx.fillRect(x, y, length, length);
 return {
 length: length,
 x: x,
 y: y,
 color: color
 };
}
export { name, draw, reportArea, reportPerimeter };
export default randomSquare;

モジュール紹介

// main.js
import { create, createReportList } from './modules/canvas.js';
import { name, draw, reportArea, reportPerimeter } from './modules/square.js';
import randomSquare from './modules/square.js';
let myCanvas = create('myCanvas', document.body, 480, 320);
let reportList = createReportList(myCanvas.id);
let square1 = draw(myCanvas.ctx, 50, 50, 100, 'blue');
reportArea(square1.length, reportList);
reportPerimeter(square1.length, reportList);
// Use the default
let square2 = randomSquare(myCanvas.ctx);

ページロード

<!DOCTYPE html>
<html lang="en-US">
 <head>
 <meta charset="utf-8">
 <title>Basic JavaScript module example</title>
 <style>
 canvas {
 border: 1px solid black;
 }
 </style>
 <script type="module" src="main.js"></script>
 </head>
 <body>
 Basic JavaScript module example 
 </body>
</html>

サーバー側コード

//index.js
const http = require('http')
const fs = require('fs')
const url = require('url')
const path = require('path')
const mime = require('mime')
http.createServer(function(request,response) {
 const urlObj = url.parse(request.url)
 const urlPathname = urlObj.pathname
 const filename = path.join(__dirname, urlPathname)
 const ext = path.parse(urlPathname).ext
 const mimeType = mime.getType(ext) || ""
 
 if(mimeType) {
 fs.readFile(filename, (err, data) => {
 console.log("mimeType:"+mimeType)
 if(err) {
 response.writeHead(404, { "Content-Type": "text/plain" });
 response.write("404 - File is not found!")
 response.end()
 }else{
 response.writeHead(200, { "Content-Type": mimeType});
 response.end(data)
 }
 })
 }else{
 const html = fs.readFileSync("./index.html",'utf-8')
 response.end(html)
 }
 
}).listen(8080,() => {
 console.log('server id dev')
})

サービスの起動

ノード index.js

ソースクローンから直接実行

終了

node index.js 最近、viteの学生が知っている必要があります気づいた、実際には、viteは、開発プロセスがパッケージ化されていない、直接ブラウザにESモジュールのソースコード出力に、ブラウザを使用して、ネイティブサポートが付属していますインポートのための各HTTPリクエストを介して、開発サーバーが直接そのような.vueファイルの要求として、コードの変換を完了するために要求を傍受する関連する変換を実施するために使用され、最終的な出力WebフロントエンドパーラーVueの父で、Vue3.0開発のアイデアのビデオのYou Yuxi深さの解釈は、You Daの言葉によると、話されている、何十倍も改善された開始とホットアップデートの効率でWebpackに比べてブラウザの受け入れ可能なリソースのために、数秒を開きます!

Read next

データ型間の変換を素早く行う

0、NaN、NULL、未定義、空文字列、ブール型に変換された5つだけが偽で、残りは真という法則があります。3つのカテゴリの合計:まず、オブジェクト==オブジェクトは、それらがメモリアドレスと比較され、アドレスが等しいと同じである場合、アドレスはnotと同じではありません。

Sep 3, 2020 · 1 min read