美文网首页
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 源码

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