importHtmlEntry 源码

index.js

抛出importEntry方法,记载入口模版

Paragraph Name

数据缓存

const styleCache = {};
const scriptCache = {};
const embedHTMLCache = {};

默认的fetch 和 获取模版函数

export function importEntry(entry, opts = {}) {
}

opts说明

const defaultFetch = window.fetch.bind(window);
function defaultGetTemplate(tpl) { return tpl; }
getPublicPath

getExternalStyleSheet 和 getExecutableScript,getExternalScripts

getExecutableScript 获取css文件内容,如果是inline格式直接返回,如果是链接,查看是否缓存放回文本


function getExecutableScript(scriptSrc, scriptText, proxy, strictGlobal) {
    const sourceUrl = isInlineCode(scriptSrc) ? '' : `//# sourceURL=${scriptSrc}\n`;

    window.proxy = proxy;
    // TODO 通过 strictGlobal 方式切换切换 with 闭包,待 with 方式坑趟平后再合并
    return strictGlobal
        ? `;(function(window, self){with(window){;${scriptText}\n${sourceUrl}}}).bind(window.proxy)(window.proxy, window.proxy);`
        : `;(function(window, self){;${scriptText}\n${sourceUrl}}).bind(window.proxy)(window.proxy, window.proxy);`;
}


execScripts获得外部的js 区分inline和链接,如果是async模式,返回一个对象,content属性能异步加载js的文件

execScripts

    const {
        fetch = defaultFetch, strictGlobal = false, success, error = () => {
        }, beforeExec = () => {
        },
    } = opts;

            const geval = (code) => {
                beforeExec();
                (0, eval)(code);
            };

用eval执行js代码,如果是strictGlobal就将所有的属性挂载在代理上,不是直接挂载在window上。

如果是入口文件:
通过util中的noteGlobalProps和getGlobalProp方法,来获取在执行代码后挂载到全局的属性,并将其包装成exports对象的形式抛出
其他文件
不是异步,执行,是异步加载并执行

getEmbedHTML 方法

请求所有外部的css并将其以style的方式嵌入html中

/**
 * convert external css link to inline style for performance optimization
 * @param template
 * @param styles
 * @param opts
 * @return embedHTML
 */
function getEmbedHTML(template, styles, opts = {}) {
    const { fetch = defaultFetch } = opts;
    let embedHTML = template;

    return getExternalStyleSheets(styles, fetch)
        .then(styleSheets => {
            embedHTML = styles.reduce((html, styleSrc, i) => {
                html = html.replace(genLinkReplaceSymbol(styleSrc), `<style>/* ${styleSrc} */${styleSheets[i]}</style>`);
                return html;
            }, embedHTML);
            return embedHTML;
        });
}

importHTML 方法

如果入口是string,就调用importHTML方法

// 通过fetch获取的html文件,经过processTpl解析
        .then(html => {
            const assetPublicPath = getPublicPath(url);
            const { template, scripts, entry, styles } = processTpl(getTemplate(html), assetPublicPath);

            return getEmbedHTML(template, styles, { fetch }).then(embedHTML => ({
                template: embedHTML,
                assetPublicPath,
                getExternalScripts: () => getExternalScripts(scripts, fetch),
                getExternalStyleSheets: () => getExternalStyleSheets(styles, fetch),
                execScripts: (proxy, strictGlobal) => {
                    if (!scripts.length) {
                        return Promise.resolve();
                    }
                    return execScripts(entry, scripts, proxy, { fetch, strictGlobal });
                },
            }));
        }));

返回值

{
                template: embedHTML, 
                assetPublicPath,
                getExternalScripts: () => getExternalScripts(scripts, fetch),
                getExternalStyleSheets: () => getExternalStyleSheets(styles, fetch),
                execScripts: (proxy, strictGlobal) => {
                    if (!scripts.length) {
                        return Promise.resolve();
                    }
                    return execScripts(entry, scripts, proxy, { fetch, strictGlobal });
                },
}

process-tpl.js

一些正则

const ALL_SCRIPT_REGEX = /(<script[\s\S]*?>)[\s\S]*?<\/script>/gi; // 所有script标签
const SCRIPT_TAG_REGEX = /<(script)\s+((?!type=('|")text\/ng-template\3).)*?>.*?<\/\1>/is; // // 不是 ng-template的script 正向否定查找
const SCRIPT_SRC_REGEX = /.*\ssrc=('|")?([^>'"\s]+)/; //script 上的 src
const SCRIPT_TYPE_REGEX = /.*\stype=('|")?([^>'"\s]+)/; // script 上的type
const SCRIPT_ENTRY_REGEX = /.*\sentry\s*.*/; // 
const SCRIPT_ASYNC_REGEX = /.*\sasync\s*.*/;
const SCRIPT_NO_MODULE_REGEX = /.*\snomodule\s*.*/;
const SCRIPT_MODULE_REGEX = /.*\stype=('|")?module('|")?\s*.*/;
const LINK_TAG_REGEX = /<(link)\s+.*?>/isg;
const LINK_PRELOAD_OR_PREFETCH_REGEX = /\srel=('|")?(preload|prefetch)\1/;
const LINK_HREF_REGEX = /.*\shref=('|")?([^>'"\s]+)/;
const LINK_AS_FONT = /.*\sas=('|")?font\1.*/;
const STYLE_TAG_REGEX = /<style[^>]*>[\s\S]*?<\/style>/gi;
const STYLE_TYPE_REGEX = /\s+rel=('|")?stylesheet\1.*/;
const STYLE_HREF_REGEX = /.*\shref=('|")?([^>'"\s]+)/;
const HTML_COMMENT_REGEX = /<!--([\s\S]*?)-->/g;
const LINK_IGNORE_REGEX = /<link(\s+|\s+.+\s+)ignore(\s*|\s+.*|=.*)>/is;
const STYLE_IGNORE_REGEX = /<style(\s+|\s+.+\s+)ignore(\s*|\s+.*|=.*)>/is;
const SCRIPT_IGNORE_REGEX = /<script(\s+|\s+.+\s+)ignore(\s*|\s+.*|=.*)>/is;

一些方法

export const genLinkReplaceSymbol = (linkHref, preloadOrPrefetch = false) => `<!-- ${preloadOrPrefetch ? 'prefetch/preload' : ''} link ${linkHref} replaced by import-html-entry -->`;
export const genScriptReplaceSymbol = (scriptSrc, async = false) => `<!-- ${async ? 'async' : ''} script ${scriptSrc} replaced by import-html-entry -->`;
export const inlineScriptReplaceSymbol = `<!-- inline scripts replaced by import-html-entry -->`;
export const genIgnoreAssetReplaceSymbol = url => `<!-- ignore asset ${url || 'file'} replaced by import-html-entry -->`;
export const genModuleScriptReplaceSymbol = (scriptSrc, moduleSupport) => `<!-- ${moduleSupport ? 'nomodule' : 'module'} script ${scriptSrc} ignored by import-html-entry -->`;

生成html中资源的说明,例如加载了‘./a.css’就会生成

processTpl 方法
处理html中的js,css以,入口文件和html模版本身,将符合条件的css和js提取出来(加载css和js的标签)并将其替换掉

    let scripts = [];
    const styles = [];
    let entry = null;
    const template = tpl
  • 去掉html的注释
  • 处理html中<link>元素相关的逻辑
        .replace(LINK_TAG_REGEX, match => {
            /* change the css link */
            code...
            return match;
        })
* 检查是否是样式文件,如果是尝试获取地址,有地址的如果是忽略直接替代成忽略标签,不是添加进styles数组,替代成样式标签。
* 如果不满足样式文件,查看是否是预加载(有地址并且不是字体文件),替代成预加载样式标签
* 都不符合,不做处理
  • 检查<style>元素,如果是忽略,替代成忽略标签
  • 检查script 元素,替代
        .replace(ALL_SCRIPT_REGEX, (match, scriptTag) => {
            // code ...
        });
* 检查是否是符合js类型的type,不符合不作处理
* 检查是否含有src,若果有采取类似link的处理,不同的是js有可能是异步async的
* 检查是否是inline-code,如果是提取出来
* 将符合条件的推入scripts数组,其他的不作处理

util.js

util 分析

  • shouldSkipProperty 是否需要跳过该全局属性(变量)

  • getGlobalProp 得到一个控制的全局属性

  • noteGlobalProps 标记全局属性

  • getInlineCode 解析script中的代码

  • defaultGetPublicPath 获得资源的public path

  • isModuleScriptSupported 是否支持模块

  • requestIdleCallback requestIdleCallback polyfill

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。