美文网首页
importHtmlEntry 源码

importHtmlEntry 源码

作者: pipu | 来源:发表于2020-09-30 11:43 被阅读0次

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

相关文章

  • importHtmlEntry 源码

    index.js 抛出importEntry方法,记载入口模版 Paragraph Name 数据缓存 默认的fe...

  • iOS-OC相关源码下载和OC代码转C++/汇编/LVVM

    目录 OC相关源码下载----objc源码----malloc源码----Runloop源码----GCD源码OC...

  • go run

    源码文件 Golang源码文件分为三种类型,分别是命令源码文件、库源码文件、测试源码文件 命令源码文件 命令源码文...

  • 文章目录汇总

    Java 源码 String源码-Java源码系列之StringInteger、Long源码-Java源码系列之I...

  • 小米便签产品级的源码

    小米便签产品级的源码 源码简介 小米便签Android源码,可以再桌面创建widget。 源码截图 源码下载 源码下载

  • 命令源码文件

    包是有源码文件组成,源码文件分为三种,库源码文件,命令源码文件,测试源码文件 命令源码文件 定义:命令源码文件是程...

  • @@程序员——看完源码记不住?掌握这套方法,Alibaba不会少

    都说大厂面试必问源码,可很多人看完MMKV 源码、Handler 源码、Binder 源码、OkHttp 源码等源...

  • 【Tip】Go语言学习:命令源码文件

    源码文件组织形式 Go语言以代码包的形式组织源码文件。有三种类型的源码文件:命令源码、库源码和测试源码。命令源码即...

  • 源码学习之Mybatis

    Mybatis源码解读 1 源码下载 学习源码之前需要先将源码下载下来,这里需要下载mybatis源码和mybat...

  • HashMap源码

    HashMap的源码,基于jdk1.7Map的源码 AbstractMap的源码 HashMap的源码

网友评论

      本文标题:importHtmlEntry 源码

      本文链接:https://www.haomeiwen.com/subject/yeyuuktx.html