离线H5及性能优化

app内H5页面离线技术和性能优化工作总结

前提:需要app native支持html文件存储(仅仅离线化html文件)

技术实现思路:

  1. 访问H5地址
  2. app识别是否有 对应版本/离线H5的html文件 (没有就去服务器下载)
  3. webview打开html
  4. 是否有js、css等静态资源(第一次没有,要花网络请求时间去请求)
  5. 静态资源做好本地缓存设置,可以设置http的response-headers缓存
  6. 渲染页面

一些注意点

  1. 离线方案中仅仅离线了HTML文件,其他的资源首次以在线形式进行访问,然后充分利用CDN缓存。
  2. 二次访问,达到离线+缓存资源实现页面快速渲染。
  3. 更新分成两部分:离线HTML文件更新,由口袋离线应用包通过资源版本号管理,每次发版会触发重新拉取;资源更新,由html中资源路径的变化控制,每次发版,资源路径会变化。
  4. 多页面部分资源尽量做到共用,做到缓存最大使用

根据业务代码目录结构打包html产物:
modules.js

const glob = require('glob');
const fs = require('fs');
const path = require('path');
const resolveApp = (pathname) => path.resolve(process.cwd(), pathname);
const APP_DIR = resolveApp('src/views/');

function handleEntryConfig(checkPath) {
	const chunk = [];
	const list = glob.sync(checkPath).map(file => {
		const data = path.parse(file);
		// 拿到.html存在对应的.js
		if (fs.existsSync(`${data.dir}${path.sep}${data.name}.js`)) {
			const dir_path = data.dir.replace(APP_DIR, '');
			// console.log('dir_path====', dir_path);
			const arr = dir_path.split(path.sep).filter(Boolean);
			const name = arr.join('_');
			let filename = '';
			if (data.name === 'index') {
				filename = name;
			} else {
				filename = `${name}_${data.name}`;
			}
			chunk.push({
				filename: `${filename}.html`,
				template: file,
				chunk: filename,
			});
			return {
				[filename]: `${data.dir}${path.sep}${data.name}.js`,
			};
		}
	});
    const entry = list.reduce(function (reduce, item) {
		return Object.assign(reduce, item);
    }, {});
    // console.log('输出页面配置=====', { entry: entry, chunk: chunk, list: list });
    return {
        chunk,
        entry,
        listEntry: list,
    };
}
module.exports = function (options) {
    let chunk = [],
        entry = {},
        list = [];
    const checkPath = `${APP_DIR}/**/*.html`; // 查找目录入口, 默认查找src/views下面所有的html
    const modules = require('../modules/')(options);
    // sirus离线打包
    if (options.pages) {
        modules.increase = [options.pages];
    }
    // dev环境pack为空或增量,increase存在配置
    if (['', 'inc'].includes(options.pack) && modules.increase.length > 0) {
        modules.increase.forEach(module => {
            const path = resolveApp(`${APP_DIR}/${module}`);
            const data = handleEntryConfig(`${path}/**/*.html`);
            // console.log('data 数据======', data);
            data.chunk.forEach(item => {
                chunk.push(item);
            });
            list = list.concat(data.listEntry);
            Object.assign(entry, data.entry);
        });
    } else if (options.pack === 'all' || modules.increase.length === 0) {
        // all 或为空则全量
        const data = handleEntryConfig(checkPath);
        chunk = data.chunk;
        entry = data.entry;
        list = list.concat(data.listEntry);
    }
    // console.log('最终输出页面配置=====', { entry: entry, chunk: chunk, listEntry: list });
    return {
        chunk,
        entry,
        listEntry: list,
    };
};

modules.js

module.exports = {
    ignore: [], // 忽略构建的模块
    increase: ['xxx/xxxxxx'], // 为空则打全量,否则构建指定的模块
};

webpack.js打包部分引入modules.js中运行出来的产物:
entry赋值给entry使用;
chunk给HtmlWebpackPlugin,打包chunk使用

性能优化部分

  1. 使用 link标签 对cdn资源域名、接口资源域名 进行提前预建联,字体文件预加载
<link rel="preconnect" href="https://cdn-xxx.xxxx.xxx.xx" />
<link rel="dns-prefetch" href="https://cdn-xxx.xxxx.xxx.xx" />
<link rel="dns-prefetch" href="https://api-xxx.xxxx.xxx.xx" />
<link rel="preload" as="font" type="font/woff2" crossorigin="anonymous" href="https://xxx.xx/woff2" />
  1. cdn资源、公用js库,不经常更新版本的设置缓存,加载缓存的文件
  2. 分屏加载组件,非首屏的组件做动态加载,降低了首屏加载的js大小
<!--第二屏渲染组件-->
<component ref="dynamicComponent" :is="comName" :prdCode="prdCode" :templateId="templateId"></component>

mounted() {
	this.$nextTick(() => {
		this.lazyLoadUnFirstBundle();
	});
}
   
lazyLoadUnFirstBundle() {
	this.comName = () =>
	import(/* webpackChunkName: "deposit_structured_detai_second_screen" */ './detail_part2.vue').then(
		m => m.default,
	);
},
  1. 首屏数据做LocalStorage的缓存,注意5M内存满了没法继续存时清空旧的
  2. 首屏渲染之后,再使用loadjs加载三方组件,比如分享、电梯、广告弹窗等js
  3. 函数、变量的引入使用按需引入
  4. 编码时考虑tree shaking
  5. 按需加载polyfill.js替代babel编译
  6. 优化FCP前的接口请求,修改接口的调用时机,非必要的接口后置,可合并的接口合并
  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值