การนำเข้า HTML

รวมสำหรับเว็บ

ทำไมต้องนำเข้า

ลองพิจารณาดูว่าคุณโหลดแหล่งข้อมูลประเภทต่างๆ บนเว็บอย่างไร ส่วน JS เรามี <script src> สำหรับ CSS หน้าที่คุณเข้าชมอาจเป็น <link rel="stylesheet"> สำหรับรูปภาพคือ <img> วิดีโอมี <video> เสียง <audio>... เข้าประเด็นเลย เนื้อหาส่วนใหญ่ในเว็บมีวิธีการที่ง่ายและชัดเจนในการโหลดตัวเอง ไม่ใช่สำหรับ HTML คุณมีตัวเลือกดังต่อไปนี้

  1. <iframe> - พยายามแล้วจริงใจแต่หนักแน่น เนื้อหาของ iframe จะอยู่ในบริบทที่แยกจากหน้าเว็บของคุณ แม้ว่าโดยส่วนใหญ่แล้วจะเป็นฟีเจอร์ที่ยอดเยี่ยม แต่ก็สร้างความท้าทายเพิ่มเติม (การย่อขนาดเฟรมให้อยู่ภายในเนื้อหาเป็นเรื่องยาก และน่าหงุดหงิดอย่างยิ่งเมื่อต้องเขียนสคริปต์เข้า/ออก และแทบไม่สามารถจัดรูปแบบได้)
  2. AJAX - ฉันชอบ xhr.responseType="document" แต่ฉันบอกว่าต้องการ JS เพื่อโหลด HTML ใช่ไหม ดูเหมือนข้อมูลจะไม่ถูกต้อง
  3. CrazyHacksTM - ฝังอยู่ในสตริงโดยซ่อนเป็นความคิดเห็น (เช่น <script type="text/html">) ไชโย!

เห็นการประชดประชันไหม HTML ที่เป็นเนื้อหาพื้นฐานที่สุดของเว็บต้องอาศัยความพยายามอย่างมากในการทำงานร่วมกัน แต่โชคดีที่คอมโพเนนต์ของเว็บพร้อมที่จะกลับมาดำเนินการต่อได้

เริ่มต้นใช้งาน

การนำเข้า HTML ซึ่งเป็นส่วนหนึ่งของการแคสต์คอมโพเนนต์เว็บเป็นวิธีการรวมเอกสาร HTML ในเอกสาร HTML อื่นๆ คุณไม่ได้จำกัดเฉพาะเรื่องมาร์กอัปด้วย การนำเข้าอาจรวมถึง CSS, JavaScript หรือสิ่งอื่นๆ ที่อยู่ในไฟล์ .html ด้วย กล่าวอีกนัยหนึ่งคือ วิธีนี้ทำให้การนำเข้าเป็นเครื่องมือที่ยอดเยี่ยมสำหรับการโหลด HTML/CSS/JS ที่เกี่ยวข้อง

ข้อมูลพื้นฐาน

รวมการนําเข้าในหน้าเว็บโดยการประกาศ <link rel="import">:

<head>
    <link rel="import" href="/path/to/imports/stuff.html">
</head>

URL ของการนำเข้าเรียกว่าตำแหน่งการนำเข้า หากต้องการโหลดเนื้อหาจากโดเมนอื่น สถานที่นำเข้าจะต้องเปิดใช้ CORS

<!-- Resources on other origins must be CORS-enabled. -->
<link rel="import" href="http://example.com/elements.html">

การตรวจจับและการสนับสนุนฟีเจอร์

หากต้องการตรวจหาการสนับสนุน ให้ตรวจสอบว่ามี .import อยู่ในองค์ประกอบ <link> หรือไม่ โดยทำดังนี้

function supportsImports() {
    return 'import' in document.createElement('link');
}

if (supportsImports()) {
    // Good to go!
} else {
    // Use other libraries/require systems to load files.
}

การรองรับเบราว์เซอร์ยังอยู่ในช่วงแรกๆ Chrome 31 เป็นเบราว์เซอร์แรกที่เห็นการติดตั้งใช้งาน แต่ผู้ให้บริการเบราว์เซอร์รายอื่นกำลังรอดูว่าโมดูล ES จะเป็นอย่างไร อย่างไรก็ตาม สำหรับเบราว์เซอร์อื่น webcomponents.js polyfill จะทำงานได้ดีที่สุดจนกว่าจะมีการรองรับในวงกว้าง

การรวมทรัพยากร

การนำเข้าทำให้มีแบบแผนสำหรับการรวม HTML/CSS/JS (แม้แต่การนำเข้า HTML อื่นๆ) ไว้ในการส่งมอบเดียว ซึ่งเป็นฟีเจอร์ภายใน แต่ทรงพลัง หากคุณกำลังสร้างธีม ไลบรารี หรือต้องการแบ่งกลุ่มแอปออกเป็นส่วนๆ การให้ URL เดียวที่น่าสนใจสำหรับผู้ใช้ อย่างไรก็ตาม คุณอาจนำส่งทั้งแอปด้วยการนำเข้าเลยก็ได้ ลองคิดเรื่องนี้ดูนะ

ตัวอย่างการใช้งานจริงคือ Bootstrap Bootstrap ประกอบด้วยไฟล์ต่างๆ (Boottrap.css, Boottrap.js, แบบอักษร) ที่จำเป็นสำหรับ JQuery สำหรับปลั๊กอิน และมีตัวอย่างมาร์กอัป นักพัฒนาแอปอย่างความยืดหยุ่นในการสั่งซื้อ ทำให้ผู้ใช้สนใจส่วนต่างๆ ของเฟรมเวิร์กที่ตัวเองต้องการใช้ อย่างไรก็ตาม ฉันจะลงเดิมพันให้ JoeDeveloperTM ทั่วไปให้คุณจะเลือกง่ายๆ และดาวน์โหลด Bootstrap ทั้งหมด

การนำเข้าเป็นเรื่องที่มีประโยชน์มากอย่าง Bootstrap อนาคตของการโหลด Bootstrap แก่คุณจะพูดถึง:

<head>
    <link rel="import" href="bootstrap.html">
</head>

ผู้ใช้เพียงแค่โหลดลิงก์การนำเข้า HTML นักเรียนจะได้ไม่ต้องยุ่งยากกับภาพแบบกระจาย แต่ทั้ง Bootstrap ได้รับการจัดการและรวมอยู่ในการนำเข้า ซึ่ง หัวข้อ Bootstrap.html คือ:

<link rel="stylesheet" href="bootstrap.css">
<link rel="stylesheet" href="fonts.css">
<script src="jquery.js"></script>
<script src="bootstrap.js"></script>
<script src="bootstrap-tooltip.js"></script>
<script src="bootstrap-dropdown.js"></script>
...

<!-- scaffolding markup -->
<template>
    ...
</template>

ปล่อยให้มันนั่งลง ช่างเป็นเรื่องน่าตื่นเต้น

เหตุการณ์การโหลด/ข้อผิดพลาด

องค์ประกอบ <link> จะทำให้เหตุการณ์ load เริ่มทำงานเมื่อโหลดการนำเข้าสำเร็จแล้ว และ onerror เมื่อนำเข้าไม่สำเร็จ (เช่น หากทรัพยากร 404)

การนําเข้าจะพยายามโหลดทันที วิธีง่ายๆ ที่ช่วยไม่ให้ปวดศีรษะ คือการใช้แอตทริบิวต์ onload/onerror ดังนี้

<script>
    function handleLoad(e) {
    console.log('Loaded import: ' + e.target.href);
    }
    function handleError(e) {
    console.log('Error loading import: ' + e.target.href);
    }
</script>

<link rel="import" href="file.html"
        onload="handleLoad(event)" onerror="handleError(event)">

หรือถ้าคุณสร้างการนำเข้าแบบไดนามิก:

var link = document.createElement('link');
link.rel = 'import';
// link.setAttribute('async', ''); // make it async!
link.href = 'file.html';
link.onload = function(e) {...};
link.onerror = function(e) {...};
document.head.appendChild(link);

การใช้เนื้อหา

การรวมการนำเข้าในหน้าไม่ได้หมายความว่า "แทรกเนื้อหาของไฟล์นั้นที่นี่" ซึ่งหมายความว่า "เครื่องมือแยกวิเคราะห์ ลบเอกสารนี้ไปเพื่อที่ฉันจะได้ใช้งาน" หากต้องการใช้เนื้อหาจริงๆ คุณจะต้องดำเนินการและเขียนสคริปต์

ช่วงเวลาที่สำคัญของ aha! ทำให้รู้ว่าการนำเข้าเป็นเพียงเอกสาร อันที่จริง เนื้อหาของการนำเข้าเรียกว่าเอกสารนำเข้า คุณจัดการข้อมูลการนำเข้าโดยใช้ DOM API มาตรฐานได้

link.import

หากต้องการเข้าถึงเนื้อหาของการนําเข้า ให้ใช้พร็อพเพอร์ตี้ .import ขององค์ประกอบลิงก์ ดังนี้

var content = document.querySelector('link[rel="import"]').import;

link.importnullภายใต้เงื่อนไขต่อไปนี้

  • เบราว์เซอร์ไม่รองรับการนำเข้า HTML
  • <link> ไม่มี rel="import"
  • ยังไม่ได้เพิ่ม <link> ลงใน DOM
  • นำ <link> ออกจาก DOM แล้ว
  • ทรัพยากรไม่ได้เปิดใช้ CORS

ตัวอย่างแบบเต็ม

สมมติว่า warnings.html มีสิ่งต่อไปนี้

<div class="warning">
    <style>
    h3 {
        color: red !important;
    }
    </style>
    <h3>Warning!
    <p>This page is under construction
</div>

<div class="outdated">
    <h3>Heads up!
    <p>This content may be out of date
</div>

ผู้นำเข้าสามารถจับบางส่วนของเอกสารนี้และโคลนในหน้าของตน:

<head>
    <link rel="import" href="warnings.html">
</head>
<body>
    ...
    <script>
    var link = document.querySelector('link[rel="import"]');
    var content = link.import;

    // Grab DOM from warning.html's document.
    var el = content.querySelector('.warning');

    document.body.appendChild(el.cloneNode(true));
    </script>
</body>

การเขียนสคริปต์ในการนำเข้า

การนำเข้าไม่อยู่ในเอกสารหลัก ดาวเทียมของเราเป็นดาวเทียม อย่างไรก็ตาม ข้อมูลการนำเข้าของคุณจะยังคงทำงานในหน้าหลักได้ แม้ว่าเอกสารหลักจะมีโดเมนเหนือกว่าก็ตาม การนําเข้าสามารถเข้าถึง DOM ของตัวเองและ/หรือ DOM ของหน้าเว็บที่นําเข้า

ตัวอย่าง - export.html ที่เพิ่มสไตล์ชีตรายการหนึ่งลงในหน้าหลัก

<link rel="stylesheet" href="http://www.example.com/styles.css">
<link rel="stylesheet" href="http://www.example.com/styles2.css">

<style>
/* Note: <style> in an import apply to the main
    document by default. That is, style tags don't need to be
    explicitly added to the main document. */
#somecontainer {
color: blue;
}
</style>
...

<script>
// importDoc references this import's document
var importDoc = document.currentScript.ownerDocument;

// mainDoc references the main document (the page that's importing us)
var mainDoc = document;

// Grab the first stylesheet from this import, clone it,
// and append it to the importing document.
    var styles = importDoc.querySelector('link[rel="stylesheet"]');
    mainDoc.head.appendChild(styles.cloneNode(true));
</script>

โปรดสังเกตสิ่งที่เกิดขึ้น สคริปต์ภายในการนำเข้าอ้างอิงเอกสารที่นำเข้า (document.currentScript.ownerDocument) และนำบางส่วนของเอกสารนั้นไปผนวกกับหน้าการนำเข้า (mainDoc.head.appendChild(...)) ค่อนข้างเข้าใจยากถ้าคุณถามฉัน

กฎของ JavaScript ในการนำเข้า

  • สคริปต์ในการนำเข้าจะทำงานในบริบทของหน้าต่างที่มี document ที่นำเข้า ดังนั้น window.document จึงหมายถึงเอกสารในหน้าหลัก ซึ่งมี Coroll ที่มีประโยชน์ 2 กลุ่ม ได้แก่
    • ฟังก์ชันต่างๆ ที่กำหนดไว้ในการนำเข้าที่สิ้นสุดในวันที่ window
    • คุณไม่ต้องทำอะไรให้ยุ่งยาก เช่น เพิ่มบล็อก <script> ของการนำเข้าต่อท้ายหน้าหลัก สคริปต์จะทำงานเช่นเดียวกัน
  • การนำเข้าไม่บล็อกการแยกวิเคราะห์หน้าหลัก อย่างไรก็ตาม สคริปต์ในสคริปต์จะได้รับการประมวลผลตามลำดับ ซึ่งหมายความว่าคุณจะได้รับลักษณะการทำงานแบบหน่วงเวลาขณะที่รักษาลำดับสคริปต์ที่เหมาะสม ดูข้อมูลเพิ่มเติมได้ที่ด้านล่าง

การแสดงคอมโพเนนต์เว็บ

การออกแบบการนำเข้า HTML สามารถโหลดเนื้อหาที่นำกลับมาใช้ใหม่ได้บนเว็บเป็นอย่างดี โดยเฉพาะอย่างยิ่ง สำหรับการเผยแพร่คอมโพเนนต์ของเว็บ ทุกอย่างตั้งแต่ HTML <template> พื้นฐานไปจนถึงองค์ประกอบที่กำหนดเองแบบเต็มรูปแบบด้วย Shadow DOM [1, 2, 3] เมื่อใช้เทคโนโลยีเหล่านี้พร้อมกัน การนําเข้าจะกลายเป็น #include สําหรับคอมโพเนนต์ของเว็บ

รวมเทมเพลต

องค์ประกอบเทมเพลต HTML มีความเหมาะสมกับการนำเข้า HTML อยู่แล้ว <template> เหมาะอย่างยิ่งสำหรับการแยกส่วนต่างๆ ของมาร์กอัปเพื่อให้แอปที่นำเข้าใช้ได้ตามต้องการ การรวมเนื้อหาใน <template> ยังมีประโยชน์เพิ่มเติมในการทำให้เนื้อหาไม่แอ็คทีฟจนกว่าจะใช้งาน กล่าวคือ สคริปต์จะไม่ทำงานจนกว่าจะมีการเพิ่มเทมเพลตไปยัง DOM) ตูม

import.html

<template>
    <h1>Hello World!</h1>
    <!-- Img is not requested until the <template> goes live. -->
    <img src="world.png">
    <script>alert("Executed when the template is activated.");</script>
</template>
index.html

<head>
    <link rel="import" href="import.html">
</head>
<body>
    <div id="container"></div>
    <script>
    var link = document.querySelector('link[rel="import"]');

    // Clone the <template> in the import.
    var template = link.import.querySelector('template');
    var clone = document.importNode(template.content, true);

    document.querySelector('#container').appendChild(clone);
    </script>
</body>

การลงทะเบียนองค์ประกอบที่กำหนดเอง

องค์ประกอบที่กำหนดเองเป็นเทคโนโลยีคอมโพเนนต์เว็บอีกตัวหนึ่งที่ทำงานกับการนำเข้า HTML ได้ดีเยี่ยม การนำเข้าสามารถเรียกใช้สคริปต์ได้ ดังนั้นเหตุใดจึงไม่กำหนด + บันทึกองค์ประกอบที่กำหนดเองของคุณเพื่อให้ผู้ใช้ไม่ต้องทำ ตั้งชื่อว่า..."การลงทะเบียนอัตโนมัติ"

elements.html

<script>
    // Define and register <say-hi>.
    var proto = Object.create(HTMLElement.prototype);

    proto.createdCallback = function() {
    this.innerHTML = 'Hello, <b>' +
                        (this.getAttribute('name') || '?') + '</b>';
    };

    document.registerElement('say-hi', {prototype: proto});
</script>

<template id="t">
    <style>
    ::content > * {
        color: red;
    }
    </style>
    <span>I'm a shadow-element using Shadow DOM!</span>
    <content></content>
</template>

<script>
    (function() {
    var importDoc = document.currentScript.ownerDocument; // importee

    // Define and register <shadow-element>
    // that uses Shadow DOM and a template.
    var proto2 = Object.create(HTMLElement.prototype);

    proto2.createdCallback = function() {
        // get template in import
        var template = importDoc.querySelector('#t');

        // import template into
        var clone = document.importNode(template.content, true);

        var root = this.createShadowRoot();
        root.appendChild(clone);
    };

    document.registerElement('shadow-element', {prototype: proto2});
    })();
</script>

การนำเข้านี้กำหนด (และลงทะเบียน) องค์ประกอบ 2 รายการ ได้แก่ <say-hi> และ <shadow-element> องค์ประกอบแรกแสดงองค์ประกอบที่กำหนดเองแบบพื้นฐานที่ลงทะเบียนตัวเองภายในการนำเข้า ตัวอย่างที่ 2 แสดงวิธีใช้งานองค์ประกอบที่กำหนดเองซึ่งสร้าง Shadow DOM จาก <template> จากนั้นลงทะเบียนตัวเอง

ส่วนที่ดีที่สุดเกี่ยวกับการลงทะเบียนองค์ประกอบที่กำหนดเองภายในการนำเข้า HTML คือผู้นำเข้าเพียงแค่ประกาศองค์ประกอบของคุณในหน้าเว็บของตน โดยไม่ต้องต่อสายไฟ

index.html

<head>
    <link rel="import" href="elements.html">
</head>
<body>
    <say-hi name="Eric"></say-hi>
    <shadow-element>
    <div>( I'm in the light dom )</div>
    </shadow-element>
</body>

ในความคิดของผม เวิร์กโฟลว์นี้เพียงอย่างเดียวทำให้การนำเข้า HTML เป็นวิธีที่ดีเยี่ยมในการแชร์คอมโพเนนต์ของเว็บ

การจัดการทรัพยากร Dependency และการนำเข้าย่อย

การนำเข้าย่อย

การรวมการนำเข้าอีกรายการหนึ่งอาจมีประโยชน์ เช่น หากต้องการใช้ซ้ำหรือขยายคอมโพเนนต์อื่น ให้ใช้การนำเข้าเพื่อโหลดองค์ประกอบอื่นๆ

ด้านล่างคือตัวอย่างจริงจาก Polymer เป็นคอมโพเนนต์แท็บใหม่ (<paper-tabs>) ที่นำการจัดวางและคอมโพเนนต์ตัวเลือกมาใช้ซ้ำ มีการจัดการทรัพยากร Dependency โดยใช้การนำเข้า HTML

Paper-tabs.html (ตัวย่อ):

<link rel="import" href="iron-selector.html">
<link rel="import" href="classes/iron-flex-layout.html">

<dom-module id="paper-tabs">
    <template>
    <style>...</style>
    <iron-selector class="layout horizonta center">
        <content select="*"></content>
    </iron-selector>
    </template>
    <script>...</script>
</dom-module>

นักพัฒนาแอปสามารถนำเข้าองค์ประกอบใหม่นี้ได้โดยใช้สิ่งต่อไปนี้

<link rel="import" href="paper-tabs.html">
<paper-tabs></paper-tabs>

เมื่อมี <iron-selector2> รุ่นใหม่ที่สุดยอดกว่าเดิมในอนาคต ก็สลับไปใช้ <iron-selector> และเริ่มใช้ได้ทันที คุณจะไม่เสียผู้ใช้เพราะการนำเข้าและคอมโพเนนต์ของเว็บ

การจัดการการขึ้นต่อกัน

เราทุกคนทราบดีว่าการโหลด JQuery มากกว่า 1 ครั้งต่อหน้าจะทำให้เกิดข้อผิดพลาด นี่จะไม่ถือเป็นปัญหาที่ใหญ่มากสำหรับคอมโพเนนต์ของเว็บใช่ไหม เมื่อมีคอมโพเนนต์หลายรายการใช้ไลบรารีเดียวกัน แต่ไม่ใช่ถ้าเราใช้การนำเข้า HTML ซึ่งสามารถใช้เพื่อจัดการทรัพยากร Dependency

การรวมไลบรารีในการนำเข้า HTML จะเป็นการกรองทรัพยากรที่ซ้ำกันโดยอัตโนมัติ เอกสารจะได้รับการแยกวิเคราะห์เพียงครั้งเดียว ระบบเรียกใช้สคริปต์เพียงครั้งเดียว ตัวอย่างเช่น สมมติว่าคุณกำหนดการนำเข้า jquery.html ที่โหลดสำเนาของ JQuery

jquery.html

<script src="http://cdn.com/jquery.js"></script>

การนำเข้านี้สามารถนำมาใช้ซ้ำได้ในการนำเข้าครั้งต่อๆ ไป เช่น

import2.html

<link rel="import" href="jquery.html">
<div>Hello, I'm import 2</div>
ajax-element.html

<link rel="import" href="jquery.html">
<link rel="import" href="import2.html">

<script>
    var proto = Object.create(HTMLElement.prototype);

    proto.makeRequest = function(url, done) {
    return $.ajax(url).done(function() {
        done();
    });
    };

    document.registerElement('ajax-element', {prototype: proto});
</script>

แม้แต่หน้าหลักเองก็สามารถรวม jquery.html ได้หากต้องใช้ไลบรารี:

<head>
    <link rel="import" href="jquery.html">
    <link rel="import" href="ajax-element.html">
</head>
<body>

...

<script>
    $(document).ready(function() {
    var el = document.createElement('ajax-element');
    el.makeRequest('http://example.com');
    });
</script>
</body>

แม้ว่า jquery.html จะถูกรวมอยู่ในโครงสร้างการนำเข้าที่หลากหลาย แต่เอกสารจะถูกเรียกและประมวลผลเพียงครั้งเดียวโดยเบราว์เซอร์ การตรวจสอบแผงเครือข่ายจะพิสูจน์ดังนี้

jquery.html ถูกขอเพียงครั้งเดียว
มีการขอ jquery.html ครั้งเดียว

ข้อพิจารณาด้านประสิทธิภาพ

การนำเข้า HTML นั้นยอดเยี่ยมมาก แต่เช่นเดียวกับเทคโนโลยีเว็บใหม่ คุณควรใช้อย่างชาญฉลาด แนวทางปฏิบัติแนะนำในการพัฒนาเว็บยังคงเป็นเช่นนั้น ข้อมูลด้านล่างคือสิ่งที่ควรทราบ

เชื่อมต่อการนำเข้า

การลดคำขอของเครือข่ายเป็นสิ่งสำคัญเสมอ หากคุณมีลิงก์การนำเข้าระดับบนสุดหลายรายการ ลองรวมลิงก์เหล่านั้นไว้ในทรัพยากรเดียวและนำเข้าไฟล์นั้น

Vulcanize เป็นเครื่องมือการสร้าง npm จากทีม Polymer ที่มีการรวมชุดการนำเข้า HTML หลายๆ ชุดเป็นไฟล์เดียว เปรียบได้กับขั้นตอนการสร้างการเชื่อมต่อสำหรับคอมโพเนนต์ของเว็บ

การนำเข้าโดยใช้การแคชเบราว์เซอร์

หลายคนลืมว่าสแต็กเครือข่ายของเบราว์เซอร์ได้รับการปรับแต่งอย่างละเอียดตลอดหลายปีที่ผ่านมา การนำเข้า (และการนำเข้าย่อย) ก็ใช้ประโยชน์จากตรรกะนี้เช่นกัน การนำเข้า http://cdn.com/bootstrap.html อาจมีทรัพยากรย่อย แต่จะมีการแคชทรัพยากรเหล่านั้นไว้

เนื้อหาจะมีประโยชน์ก็ต่อเมื่อคุณเพิ่มเนื้อหาเท่านั้น

ให้คิดว่าเนื้อหาไม่มีความสมเหตุสมผลจนกว่าคุณจะเรียกใช้บริการของเนื้อหานั้น ใช้สไตล์ชีตปกติที่สร้างแบบไดนามิก:

var link = document.createElement('link');
link.rel = 'stylesheet';
link.href = 'styles.css';

เบราว์เซอร์จะไม่ขอ style.css จนกว่าจะเพิ่ม link ลงใน DOM

document.head.appendChild(link); // browser requests styles.css

อีกตัวอย่างหนึ่งคือมาร์กอัปที่สร้างขึ้นแบบไดนามิก

var h2 = document.createElement('h2');
h2.textContent = 'Booyah!';

h2 ค่อนข้างไม่มีความหมายจนกว่าคุณจะเพิ่มลงใน DOM

แนวคิดเดียวกันนี้เป็นจริงสำหรับเอกสารนำเข้า คุณจะไม่สามารถดำเนินการทดสอบเนื้อหาได้ อันที่จริง สิ่งเดียวที่ "เรียกใช้" ในเอกสารนำเข้าโดยตรงคือ <script> เว้นแต่ว่าคุณจะเพิ่มเนื้อหาต่อท้าย DOM ดูการเขียนสคริปต์ในการนำเข้า

กำลังเพิ่มประสิทธิภาพสำหรับการโหลดแบบไม่พร้อมกัน

นำเข้าการแสดงผลแบบบล็อก

การนำเข้าจะบล็อกการแสดงผลของหน้าหลัก การดำเนินการนี้คล้ายคลึงกับสิ่งที่ <link rel="stylesheet"> ทำ เหตุผลที่เบราว์เซอร์บล็อกการแสดงผลบนสไตล์ชีตตั้งแต่แรกคือเพื่อลด FOUC การนำเข้าจะทำงานในลักษณะเดียวกันเนื่องจากอาจมีสไตล์ชีต

หากต้องการให้ทำงานไม่พร้อมกันอย่างสมบูรณ์และไม่บล็อกโปรแกรมแยกวิเคราะห์หรือการแสดงผล ให้ใช้แอตทริบิวต์ async ดังนี้

<link rel="import" href="/path/to/import_that_takes_5secs.html" async>

เหตุผลที่ async ไม่ใช่ค่าเริ่มต้นสำหรับการนำเข้า HTML ก็เพราะกำหนดให้นักพัฒนาซอฟต์แวร์ต้องทำงานได้มากขึ้น แบบซิงโครนัสตามค่าเริ่มต้นหมายความว่า การนำเข้า HTML ที่มีการกำหนดองค์ประกอบที่กำหนดเองภายในองค์ประกอบนั้นจะได้รับการรับประกันว่าจะโหลดและอัปเกรดตามลำดับ บนโลกที่ไม่พร้อมกันโดยสิ้นเชิง นักพัฒนาแอปจะต้องจัดการเวลาในการเต้นและการอัปเกรดด้วยตนเอง

นอกจากนี้คุณยังสร้างการนําเข้าแบบไม่พร้อมกันแบบไดนามิกได้ ดังนี้

var l = document.createElement('link');
l.rel = 'import';
l.href = 'elements.html';
l.setAttribute('async', '');
l.onload = function(e) { ... };

การนำเข้าไม่บล็อกการแยกวิเคราะห์

การนำเข้าไม่บล็อกการแยกวิเคราะห์หน้าหลัก สคริปต์ภายในการนำเข้าจะได้รับการประมวลผลตามลำดับ แต่จะไม่บล็อกหน้าการนำเข้า ซึ่งหมายความว่าคุณจะได้รับลักษณะการทำงานแบบหน่วงเวลาขณะที่รักษาลำดับสคริปต์ที่เหมาะสม ประโยชน์อย่างหนึ่งของการนำการนำเข้าไปไว้ใน <head> คือการทำให้โปรแกรมแยกวิเคราะห์เริ่มทำงานกับเนื้อหาได้โดยเร็วที่สุด อย่างไรก็ตาม คุณต้องจำไว้ว่า <script> ในเอกสารหลักยังคงยังคงบล็อกหน้าเว็บอยู่ <script> แรกหลังจากการนำเข้าจะบล็อกการแสดงผลหน้าเว็บ เนื่องจากการนำเข้าอาจมีสคริปต์อยู่ด้านใน ซึ่งจำเป็นต้องดำเนินการก่อนสคริปต์ในหน้าหลัก

<head>
    <link rel="import" href="/path/to/import_that_takes_5secs.html">
    <script>console.log('I block page rendering');</script>
</head>

คุณสามารถเพิ่มประสิทธิภาพการทำงานแบบไม่พร้อมกันได้หลายวิธี ทั้งนี้ขึ้นอยู่กับโครงสร้างแอปและ Use Case ของคุณ เทคนิคด้านล่างจะช่วยลดการบล็อกการแสดงหน้าหลัก

สถานการณ์ที่ 1 (แนะนำ): คุณไม่มีสคริปต์ใน <head> หรืออยู่ในภาษา <body>

คำแนะนำของฉันสำหรับการวางไว้ <script> คือควรหลีกเลี่ยงการนำเข้าทันที ย้ายสคริปต์ให้เร็วที่สุดเท่าที่จะเป็นไปได้ภายในเกม...แต่คุณก็ทำตามแนวทางปฏิบัติที่ดีที่สุดแล้วใช่ไหม ;)

ตัวอย่าง

<head>
    <link rel="import" href="/path/to/import.html">
    <link rel="import" href="/path/to/import2.html">
    <!-- avoid including script -->
</head>
<body>
    <!-- avoid including script -->

    <div id="container"></div>

    <!-- avoid including script -->
    ...

    <script>
    // Other scripts n' stuff.

    // Bring in the import content.
    var link = document.querySelector('link[rel="import"]');
    var post = link.import.querySelector('#blog-post');

    var container = document.querySelector('#container');
    container.appendChild(post.cloneNode(true));
    </script>
</body>

ทุกอย่างจะอยู่ที่ด้านล่าง

สถานการณ์ 1.5: การนําเข้าจะเพิ่มตัวเอง

อีกทางเลือกหนึ่งคือให้การนำเข้าเพิ่มเนื้อหาของตัวเอง หากผู้เขียนการนำเข้าทำสัญญาให้นักพัฒนาแอปทำตาม การนำเข้าจะเพิ่มตัวเองลงในพื้นที่ของหน้าหลักได้ ดังนี้

import.html:

<div id="blog-post">...</div>
<script>
    var me = document.currentScript.ownerDocument;
    var post = me.querySelector('#blog-post');

    var container = document.querySelector('#container');
    container.appendChild(post.cloneNode(true));
</script>
index.html

<head>
    <link rel="import" href="/path/to/import.html">
</head>
<body>
    <!-- no need for script. the import takes care of things -->
</body>

สถานการณ์ #2: คุณมีสคริปต์ใน <head> หรือแทรกใน <body>

หากคุณมีการนำเข้าที่ใช้เวลาโหลดนาน <script> แรกที่ตามมาในหน้าจะบล็อกหน้าเว็บไม่ให้แสดง ตัวอย่างเช่น Google Analytics แนะนำให้วางโค้ดติดตามใน <head> หากคุณหลีกเลี่ยงการใส่ <script> ใน <head> ไม่ได้ การเพิ่มการนำเข้าแบบไดนามิกจะป้องกันการบล็อกหน้าเว็บ ดังนี้

<head>
    <script>
    function addImportLink(url) {
        var link = document.createElement('link');
        link.rel = 'import';
        link.href = url;
        link.onload = function(e) {
        var post = this.import.querySelector('#blog-post');

        var container = document.querySelector('#container');
        container.appendChild(post.cloneNode(true));
        };
        document.head.appendChild(link);
    }

    addImportLink('/path/to/import.html'); // Import is added early :)
    </script>
    <script>
    // other scripts
    </script>
</head>
<body>
    <div id="container"></div>
    ...
</body>

หรือเพิ่มการนำเข้าใกล้กับส่วนท้ายของ <body> ดังนี้

<head>
    <script>
    // other scripts
    </script>
</head>
<body>
    <div id="container"></div>
    ...

    <script>
    function addImportLink(url) { ... }

    addImportLink('/path/to/import.html'); // Import is added very late :(
    </script>
</body>

ข้อควรจำ

  • Mimetype ของการนำเข้าคือ text/html

  • ทรัพยากรจากแหล่งที่มาอื่นๆ ต้องเปิดใช้ CORS

  • ระบบจะดึงข้อมูลและแยกวิเคราะห์การนําเข้าจาก URL เดียวกันเพียงครั้งเดียว ซึ่งหมายความว่าสคริปต์ในการนำเข้าจะทำงานเฉพาะเมื่อเห็นการนำเข้าเป็นครั้งแรก

  • สคริปต์ในการนำเข้าจะได้รับการประมวลผลตามลำดับ แต่จะไม่บล็อกการแยกวิเคราะห์เอกสารหลัก

  • ลิงก์นำเข้าไม่ได้หมายถึง "#include the content here" ซึ่งหมายความว่า "เครื่องมือแยกวิเคราะห์ ลบเอกสารนี้ไปเพื่อที่ฉันจะได้ใช้ในภายหลัง" ในขณะที่สคริปต์ทำงานขณะนำเข้า จะต้องเพิ่มสไตล์ชีต มาร์กอัป และทรัพยากรอื่นๆ ลงในหน้าหลักอย่างชัดเจน โปรดทราบว่าไม่จําเป็นต้องเพิ่ม <style> อย่างชัดเจน นี่เป็นความแตกต่างที่สำคัญระหว่างการนำเข้า HTML และ <iframe> ซึ่งระบุว่า "โหลดและแสดงผลเนื้อหานี้ที่นี่"

บทสรุป

การนำเข้า HTML ช่วยให้รวม HTML/CSS/JS ไว้เป็นทรัพยากรเดียว แม้จะมีประโยชน์เพียงตัวมันเอง แต่ไอเดียนี้กลับมีศักยภาพสูงในโลกของคอมโพเนนต์เว็บ นักพัฒนาแอปสามารถสร้างคอมโพเนนต์ที่นำกลับมาใช้ใหม่ได้เพื่อให้ผู้อื่นใช้และนำเข้าในแอปของตน โดยทั้งหมดนี้ทำได้ผ่าน <link rel="import">

การนำเข้า HTML เป็นแนวคิดง่ายๆ แต่ทำให้เกิดกรณีการใช้งานที่น่าสนใจจำนวนมากสำหรับแพลตฟอร์ม

Use Case

  • แจกจ่าย HTML/CSS/JS ที่เกี่ยวข้องเป็นชุดเดียว ในทางทฤษฎีแล้ว คุณสามารถนำเข้าเว็บแอปทั้งแอปไปยังอีกแอปได้
  • การจัดระเบียบโค้ด - แบ่งแนวคิดออกเป็นกลุ่มๆ ตามหลักเหตุผลเป็นไฟล์ต่างๆ เพื่อกระตุ้นให้เกิดการแยกโมดูลและนำมาใช้ใหม่ได้**
  • ส่งคำจำกัดความขององค์ประกอบที่กำหนดเองอย่างน้อย 1 รายการ การนำเข้าสามารถใช้เพื่อregisterและรวมไว้ในแอปได้ วิธีนี้จะใช้รูปแบบของซอฟต์แวร์ที่ดี ทำให้อินเทอร์เฟซ/คำจำกัดความขององค์ประกอบแยกจากการใช้งาน
  • จัดการทรัพยากร Dependency - ระบบจะลบทรัพยากรที่ซ้ำกันออกโดยอัตโนมัติ
  • สคริปต์ส่วน - ก่อนการนำเข้า ไลบรารี JS ขนาดใหญ่จะมีการแยกวิเคราะห์ไฟล์ทั้งหมดเพื่อเริ่มต้นการทำงาน ซึ่งเป็นไฟล์ที่ช้า การนำเข้าจะทำให้ไลบรารีเริ่มทำงานได้ทันทีที่มีการแยกวิเคราะห์กลุ่ม A ใช้เวลาในการตอบสนองน้อยลง
// TODO: DevSite - Code sample removed as it used inline event handlers
  • แยกวิเคราะห์ HTML พร้อมกัน - ครั้งแรกที่เบราว์เซอร์สามารถเรียกใช้โปรแกรมแยกวิเคราะห์ HTML 2 รายการ (ขึ้นไป) พร้อมกันได้

  • เปิดใช้การสลับระหว่างโหมดแก้ไขข้อบกพร่องกับไม่ใช่โหมดแก้ไขข้อบกพร่องในแอป เพียงเปลี่ยนเป้าหมายการนำเข้า แอปของคุณไม่จำเป็นต้องทราบว่าเป้าหมายการนำเข้าคือทรัพยากรแบบรวม/คอมไพล์หรือเป็นโครงสร้างการนำเข้า