preface

Hello everyone! I’m front-end nameless

background

In practice, we often use Lottie- Web to achieve animation effects. A Lottie animation typically consists of a data.json file and N images. The Lottie animation used in the project is usually given the animation address of a CDN, which is handed over to lottie-Web library for playback. The downloading time of animation resources is to download data.json files and image resources before the animation is played. The playing of animation is greatly affected by network factors, and the loading time of animation is long. If multiple Lottie animations are required to be displayed in combination, the timing will not fit perfectly and the end result will not be as desired by the UI designer.

This article describes how to extract lootie animation resources and use caching technology to read and load Lottie animation locally, reducing network requests.

Technical approaches

  1. The Lottie Config file that needs to be cached is configured in the project.
  2. With the WebPack plug-in, the actual configuration list (the list of images and Lottie’s data.json list) that needs to be cached is generated at project build time.
  3. Wrapper preloaded libraries that request images and data.json resources stored in indexDB.
  4. Encapsulate Lottie load configuration classes that distinguish between reading from the cache and fetching directly from the network.
  5. The cache reads, creates the image Blob URL, replaces the image reference in the original data.json, and generates a new data.json.
  6. Lottie loads the configuration and displays the animation.

Understand the Lottie JSON file data format

For details, see: Web Frame Animation Solution – Lottie – Web source code Anatomy

This paper introduces the structure of Lottie JSON file with the help of Qingzhou’s picture, so as to facilitate the subsequent parsing of JSON file, reading of picture resources and replacing the picture address.

  1. JSON file global information

On the left is the information that needs to be filled in for new animation composition using AE, corresponding to the first JSON information on the right is as follows:

  • W and H: width and height
  • V: Bodymovin plugin version 4.5.4
  • Fr: frame rate
  • IP and OP: start frame, end frame
  • Assets: static information (such as pictures)
  • Layers: Layer information
  • DDD: Indicates whether it is 3D
  • Comps: Composite layers

Assets are particularly important for us to extract Lottie resources and generate new JSON.

Lottie JSON image resource extraction

There are two options for preloading Lottie images:

Scheme 1: Write webpack plug-in, extract Lottie JSON image resources during construction, and insert the image resource address into the image HTML in Link mode according to hooks provided by HTML-webpack-plugin.

Scheme 2: Write webPack plug-in, extract Lottie JSON image resources during construction, and generate Lottieassets.js configuration file. Using the cache library, read configuration files and cache resource images into indexDB.

Solution 3: Scheme 3 is basically the same as Scheme 2, in that the lottieassets. js configuration file is generated by extracting Lottie resources in different ways. Scheme 2 uses webpack plug-in, and Scheme 3 uses NPM (Lottie-extract-Assets) package to execute separate commands directly. To extract Lottie resources to generate Lottieassets.js. (production line scheme) plug-in source address: point me!

LottieConfig. Json is written in the following format:

[
    / / ceremonyBlessingBagFirst Lottie animation
    "https://xxx.com/effects/ceremonyBlessingBagFirst/data.json".ABC / / Lottie animation
    "https://xxx.com/effects/abc/data.json"./ / Lottie animation cde
    "https://xxx.com/effects/cde/data.json"
]
Copy the code

Implementation of Scheme 1:

For example, the CND address of data.json is:

Xxx.com/effects/cer…

Generally our image resources are located at xxx.com/effects/cer… directory

Code reference:

const HtmlWebpackPlugin = require('safe-require') ('html-webpack-plugin');
const lottieConfig = require(".. /.. /lottieConfig.json");
const ajax = require('.. /utils/ajax');
const request = require('request');
const path = require('path');

const preloadDirective = {
    '.js': 'script'.'.css': 'style'.'.woff': 'font'.'.woff2': 'font'.'.jpeg': 'image'.'.jpg': 'image'.'.gif': 'image'.'.png': 'image'.'.svg': 'image'
  };

const IS = {
    isDefined: v= >v ! = =undefined.isObject: v= >v ! = =null&& v ! = =undefined && typeof v === 'object'&&!Array.isArray(v),
    isBoolean: v= > v === true || v === false.isNumber: v= >v ! = =undefined && (typeof v === 'number' || v instanceof Number) && isFinite(v),
    isString: v= >v ! = =null&& v ! = =undefined && (typeof v === 'string' || v instanceof String),
    isArray: v= > Array.isArray(v),
    isFunction: v= > typeof v === 'function'
  };
  
  const { isDefined, isObject, isBoolean, isNumber, isString, isArray, isFunction } = IS;
  
  /** ** Preload image resources *@class LottieWebpackPlugin* /
  class LottieWebpackPlugin{

      constructor(options){
          this.options=options || {};
      }
      /** ** * Add image resources *@memberOf LottieWebpackPlugin* /
      addLinks= async(compilation, htmlPluginData)=>{
          let imgArray=[];
          if(lottieConfig){
              for(let i=0; i<lottieConfig.length; i++){const result=  await this.requestLottie(lottieConfig[i]);
               imgArray.push(...result);
              }
          }
          // Important: Add a preloaded link tag to the head of the htmlPlugin
          Array.prototype.push.apply(htmlPluginData.headTags, imgArray.map(this.addPreloadType));
        return htmlPluginData;
      }
      /** ** * request data.json file *@memberOf LottieWebpackPlugin* /
      requestLottie=  (url) = >{
         return new Promise((resolve,reject) = >{
            request(url,  (error, response, body) = > {
                if(! error && response.statusCode ==200) {
                  try{
                    const lottieData=JSON.parse(body);
                    const result= this.lottieParse(lottieData,url);
                    resolve(result);
                  }catch(e){
                      console.log(e); }}else{
                    reject(url+"Failure"); }})})}/** ** * Parse Lottie files *@memberOf LottieWebpackPlugin* /
      lottieParse=(data,url) = >{
        let urlArray=[];
        try{
            const assets=data.assets;
            const urlPre=this.getUrlPre(url);
            for(let i=0; i<assets.length; i++){const item=assets[i];
                if(item.p && item.u){
                    const url=`${urlPre}${item.u}${item.p}`;
                    const tag= this.createResourceHintTag(url,"preload".true); urlArray.push(tag); }}}catch(e){
              console.log(e);
          }
          return urlArray;
      }
    /** ** * gets the reference address of data.json *@memberOf LottieWebpackPlugin* /
    getUrlPre=(url) = >{
        const lastIndex=  url.lastIndexOf("/");
        return url.substring(0,lastIndex+1);
    }
    /** ** **@memberOf LottieWebpackPlugin* /
    addPreloadType =(tag) = > {
        const ext = path.extname(tag.attributes.href);
        if (preloadDirective[ext]) {
          tag.attributes.as = preloadDirective[ext];
        }
        return tag;
      }
      

      /** ** * Resource loading *@memberOf LottieWebpackPlugin* /
      alterAssetTagGroups=(htmlPluginData,callback,compilation) = >{
          console.log("compilation=",compilation);
          console.log("htmlPluginData=",htmlPluginData);
        try {
            callback(null.this.addLinks(compilation, htmlPluginData));
        } catch(error) { callback(error); }}/** ** * Create a resource link label and preload *@memberOf LottieWebpackPlugin* /
     createResourceHintTag= (url, resourceHintType, htmlWebpackPluginOptions) = > {
        return {
          tagName: 'link'.selfClosingTag:  true| |!!!!! htmlWebpackPluginOptions.xhtml,attributes: {
            rel: resourceHintType,
            href: url
          }
        };
      }
  
      registerHook(compilation){
        const pluginName=this.constructor.name; 
        if (HtmlWebpackPlugin && HtmlWebpackPlugin.getHooks) {
                // HtmlWebpackPlugin >= 4
            const hooks = HtmlWebpackPlugin.getHooks(compilation);
            const htmlPlugins = compilation.options.plugins.filter(plugin= > plugin instanceof HtmlWebpackPlugin);
            if (htmlPlugins.length === 0) {
                const message = "Error running html-webpack-tags-plugin, are you sure you have html-webpack-plugin before it in your webpack config's plugins?";
                throw new Error(message);
            }
            hooks.alterAssetTagGroups.tapAsync(pluginName, (htmlPluginData, callback) = >{this.alterAssetTagGroups(htmlPluginData, callback,compilation)});
        
        } else if (compilation.hooks.htmlWebpackPluginAlterAssetTags &&
            compilation.hooks.htmlWebpackPluginBeforeHtmlGeneration) {
                // HtmlWebpackPlugin 3
                compilation.hooks.htmlWebpackPluginAlterAssetTags.tapAsync(pluginName,(htmlPluginData, callback) = >{this.alterAssetTagGroups(htmlPluginData, callback,compilation)});
        }else{
            const message = "Error running html-webpack-tags-plugin, are you sure you have html-webpack-plugin before it in your webpack config's plugins?";
            throw new Error(message); }}apply(compiler){
        const htmlPluginName = isDefined(this.options.htmlPluginName) ? this.options.htmlPluginName : 'html-webpack-plugin';
        const pluginName=this.constructor.name;
          if(compiler.hooks){
              compiler.hooks.compilation.tap(pluginName,(compilation) = >{
                  this.registerHook(compilation); }); }}}module.exports = LottieWebpackPlugin;
Copy the code

The generated HTML looks like this:

Making stamp: Lottie – pre – webpack – the plugin

Scheme 2: customized Webpack plug-in, extract image resources, generate JS or TS files

Code reference:

const fs = require('fs');
const request = require('request');
const path = require('path');
const webpack = require("webpack");

/** ** Lottie Resource extraction plug-in *@class LottieExtractAssetsPlugin* /
class LottieExtractAssetsPlugin {

    constructor (options) {
    	//1: obtain the Lottie configuration file path
        this.configPath = options && options.configPath;
        //2: get the output file name
        this.outFileName = options && options.outFileName ? options.outFileName : "lottie-assets.js";
        // Generate the global name of the resource file
        this.globalName = options && options.globalName ? options.globalName : "window._config";
        this.to = options && options.to ? options.to : "dist";
    }

    compilationHook(compilation) {
        const pluginName = this.constructor.name;
        // Key: Webpack fit
        if(compilation.hooks.processAssets){
            //compilation.emitAsset(name, new webpack.sources.RawSource(html, false));
           // Add resources
            compilation.hooks.processAssets.tapAsync({ name: pluginName, stage: webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS }, async (assets, cb) => {
                if (this.configPath) {
                    await this.readJsonFile(this.configPath, assets);
                    cb();
                } else{ cb(); }}); }else if(compilation.hooks.additionalAssets){
            compilation.hooks.additionalAssets.tapAsync( pluginName,  async (cb) => {
                if (this.configPath) {
                    await this.readJsonFile(this.configPath, compilation.assets);
                    cb();
                } else{ cb(); }}); }else{
            //throw new Error(" Please update webpack version >=4");
            compilation.errors.push("Update webpack version >=4"); }}/** ** * Obtain the Lottie resource address. *@memberOf LottieExtractAssetsPlugin* /
    getLink= async(lottieConfig)=>{
        let imgArray=[];
        if(lottieConfig){
            for(let i=0; i<lottieConfig.length; i++){const url=lottieConfig[i];
                // Add Lottie JSON
                this.addLottieInfo(url,imgArray);
                // Request the Lottie JSON file to obtain the image resource
                const result=  await this.requestLottie(lottieConfig[i]);
                imgArray.push(...result);
            }
        }
      return imgArray;
    }
    /** ** * Add Lottie JSON file *@memberOf LottieExtractAssetsPlugin* /
    addLottieInfo=(url,imgArr) = >{
        const info=this.getLottieInfo(url);
        imgArr.push({
            key:info.name,
            url:url,
         })
    }
    
    /** ** * Read the configuration file to generate the JS file. *@memberOf LottieExtractAssetsPlugin* /
    readJsonFile= async(assetPath,assets)=>{
        // Read the lottieCofig. Json configuration file
        let lottieConfig = await new Promise((resolve, reject) = > {
            try {
                // Read the configuration file
                fs.readFile(assetPath, (err, data) = > {
                    if (err) {
                        reject(err);
                    } else {
                        let curData = data.toString();
                        const config = JSON.parse(curData); resolve(config); }}); }catch (e) {
                reject(e);
            }
        }).catch(() = >{
            console.warn(Error reading configuration file:+assetPath);
        });
        if(! lottieConfig){return;
        }
        // Get resource links based on configuration (including current Lottie and images in Lottie)
        const imgLink = await this.getLink(lottieConfig);
        // Use js file, convenient for our front-end code integration use.
        let content = this.globalName + "=" + JSON.stringify(imgLink, null.4) + ";";
        const assetsInfo = {
            // Write the contents of the new file
            source: function () {
                return content;
            },
            // New file size (for webapck output display)
            size: function () {
                returncontent.length; }}const fileName = path.join(this.to, this.outFileName);
        assets[fileName]= assetsInfo;
    }
    /** ** * Request Lottie JSON file *@memberOf LottieExtractAssetsPlugin* /
    requestLottie=  (url) = >{
       return new Promise((resolve,reject) = >{
          request(url,  (error, response, body) = > {
              if(! error && response.statusCode ==200) {
                try{
                  const lottieData=JSON.parse(body);
                  const result= this.lottieParse(lottieData,url);
                  resolve(result);
                }catch(e){
                    console.log(e); }}else{
                  reject(url+= = "failure"); }})})}/** ** parse Lottie *@memberOf LottieExtractAssetsPlugin* /
    lottieParse=(data,url) = >{
      let urlArray=[];
      try{
          const assets=data.assets;
          const lottieInfo=this.getLottieInfo(url);
          for(let i=0; i<assets.length; i++){const item=assets[i];
              if(item.p && item.u){
                  const imgUrl=`${lottieInfo.url}/${item.u}${item.p}`;
                  urlArray.push({
                      key:`${lottieInfo.name}_${item.p}`.url:imgUrl,
                      source:url,
                      lottieName:lottieInfo.name }); }}}catch(e){
            console.log(e);
        }
        return urlArray;
    }
    /** ** Obtain Lottie information based on the URL to facilitate configuration file generation. *@memberOf LottieExtractAssetsPlugin* /
    getLottieInfo=(url) = >{
      const lastIndex=  url.lastIndexOf("/");
      const curUrlPre=url.substring(0,lastIndex);
      const nameLastIndex=  curUrlPre.lastIndexOf("/");
      return {url:curUrlPre,name:curUrlPre.substring(nameLastIndex+1,nameLastIndex.length)}
    }
    /** ** Webpack plugin entry *@param {any} compiler 
     * 
     * @memberOf LottieExtractAssetsPlugin* /
    apply(compiler) {
        const pluginName=this.constructor.name;
        if(compiler.hooks){
            // Webpack 4+ Plugin System
            //TODO uses this hooks to satisfy the requirements for now, but will warn you later to check the webPack lifecycle, replace.
            compiler.hooks.compilation.tap(pluginName, (compilation, compilationParams) = > {
                // Note the timing of the registration event.
                this.compilationHook(compilation);
            });
        }else{
            compilation.errors.push("Update webpack version >=4"); }}}module.exports = LottieExtractAssetsPlugin;

Copy the code

Test plugin: webPackconfig.js:

const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const LottieExtractAssetsPlugin=require("./src/plugins/index.js");
const assert = require('assert');

const to=path.join("lottie"."test");

module.exports = {
  entry: './src/index.js'.output: {
    filename: '[name].bundle.js'.path: path.resolve(__dirname, 'dist')},plugins: [
    new CleanWebpackPlugin(),
    new LottieExtractAssetsPlugin({configPath:"./lottieConfig.json".to:to,outFileName:"lottie-assets.js".globalName:"window._lottieConfig"}})]Copy the code

Result: lottie-assets.js

Making stamp: Lottie – extract – assets – the plugin

Leverage caching to cache Lottie resources

  1. Resource IndexDB is stored

    Rloader is implemented based on IDB library.

    Rloader features:

    1. Resource loading supports simple dependencies

    2. Cache supported versions

    3. small

    4. Progress, error, completion and other events support

The encapsulation of the library was completed by Xiangenhu. Open source :rloader. The test case takes 3 seconds to load for the first time and 22 milliseconds to load later. Efficiency has been greatly improved. Rloader demo, now published nuggets: An unarmed resource loader

Specific use: index.js

import ResourceLoader from "./r-loader.js";
/ / key global cache resources: string, blobUrl: string; data:Blob,url:string;
 window.GlobCache={};

// Custom cached files by default, optional
let resourcesInfo = [
    {
        key: "mqtt2".url: "//xxx.com/libs/js/mqtt.min.js"}, {key: "lottie".url: "//xxx.com/lib/lottie.min.js".ver: "1.9"}, {key: "flv".pre: ["mqtt"].url: "/ / xxx.com/libs/js/flv.1.5.min.js"}, {pre: ["lottie"].key: "mqtt".url: "//xxx.com/libs/js/mqtt.min.js"},];// Focus on the introduction of Lottie-assets.js in index.html
if(window._config){
    // Load the Lottie resource file extracted by lottie-extract-assets-plugin
    resourcesInfo=resourcesInfo.concat(window._config);
}



let startTime=Date.now();

const rl = new ResourceLoader(resourcesInfo, window.idb);

rl.on("progress".(progress, info) = >{
    // Add a file to the global cache.
    window.GlobCache[info.key]=info;
});

rl.on("completed".(datas) = >{
    console.log("Loading completed: completed event:", datas);    
    console.log("total time:".Date.now() - startTime)
});

rl.on("loaded".(datas) = >{
    console.log("全部正常加载:loaded event:", datas);    
    console.log("total time:".Date.now() - startTime)
});

rl.on("error".(error, info) = >{
    console.log("error event:", error.message, info);
});
rl.reset();
rl.startLoad();


Copy the code

Effect:

Write Lottie Option generation method to determine whether cache read or fetch the network directly

We have cached the Lottie image resources and data.json resources in IndexDB and stored them in window.globCache. Now we can generate different Lottie Option objects based on the cache

  const jsonPath="https://xxx/acts-effects/luck-draw-act-effect1/data.json";
  const defaultOptions = {
       loop: false.autoplay: false.path: jsonPath,
       rendererSettings: {
          preserveAspectRatio: "xMidYMid slice",}};Copy the code

As we all know, Lottie needs an option object when loading an animation:

  • The resource is fetched from the cache and assigned to animationData in option. The JSON data of animationData is our modified JSON object. The image resource address is the BLOB URL
  • The resource is taken from the network and assigned to path in option

Directly to the code: lottieOptionFactory.js

/** ** Obtain the JSON object *@export
 * @param {any} rul 
 */
 export function fetchResourceJson(url){
   return fetch(url,{
        headers: {
            'content-type': 'application/json'
          },
    }).then(res= >{
        if(res.status >= 400) {throw new Error(res.status + "," + res.statusText);
        }
        return res.json();
    }).then(res= > res);
 }

/** ** Lottie Option generation *@export
 * @param {any} option 
 * @returns * /
export default async function LottieOptionFactory(option={},globCache=window.GlobCache) {
   // Get the original option
    const{ path, ... other } = option;constoriginalOption = { path, ... other, };try{
        const result = getLottieInfo(path);
        // Get the Lottie animation name
        const { name } = result;
        // Get Lottie's data.json from the global cache
        const lottieCache= globCache[name];
        // If it does not exist in the cache, return the original configuration option, which is normally obtained from the network.
        if(! lottieCache || ! lottieCache.blobUrl){return originalOption;
        }
        // Get the data.json object using blobUrl of the data.json resource retrieved from the cache
        const jsonData= await getLottieJson(lottieCache.blobUrl);
        // Modify the picture field in the Lottie JSON object
        const transJson= transformLottieJson(jsonData,name);
        // Returns data.json of the blob URL
        return {
                ...other,
                animationData:transJson
            }
    }catch(e){
        console.log("LottieOptionFactory err:",e);
    }
    return originalOption;
   
}

/** ** Obtain Lottie information based on the URL. *@memberOf getLottieInfo* /
function getLottieInfo(url) {
    const lastIndex = url.lastIndexOf("/");
    const name = url.substring(lastIndex + 1, url.length);
    const curUrlPre = url.substring(0, lastIndex);
    const nameLastIndex = curUrlPre.lastIndexOf("/");
    return { url: curUrlPre, name: curUrlPre.substring(nameLastIndex + 1, nameLastIndex.length), jsonName: name };
}

/** ** Get the Lottie JSON object *@param {any} lottieCacheData 
 * @returns * /
 function getLottieJson (url){
     // There are two implementations,
     //1: retrieves the Blob object of 'data.json' from the cache and converts the Blob object to json
     // const reader = new FileReader();
     // return new Promise((resolve,reject)=>{
     // reader.readAsText(lottieCacheData,'utf8');
     // reader.onload = function(){
     // const receive_data = this.result; // This is the parsed data
     // try{
     // resolve(JSON.parse(receive_data));
     // }catch(e){
     // console.log(" parse ",e);
     // reject(" reject ");
     / /}
     / /}
     // })
    // 2: Access the blob URL of 'data.json' directly to get the JSON object
    return fetchResourceJson(url);
    
}

/** ** Modify the image field in the Lottie JSON object to generate the image address using the BLOB URL *@param {any} lottieJson 
 * @param {any} lottieName 
 * @returns * /
function transformLottieJson (lottieJson,lottieName){
    / / backup first
    constnewLottieJson={... lottieJson};try{
        const assets=newLottieJson.assets;
        for(let i=0; i<assets.length; i++){const item=assets[i];
            //p is the image name u: the relative path of the image
            if(item.p && item.u){
                const name=`${lottieName}_${item.p}`;
                const lottieCache= window.GlobCache[name];
                if(lottieCache && lottieCache.blobUrl){
                    newLottieJson.assets[i].u=""; newLottieJson.assets[i].p=lottieCache.blobUrl; }}}}catch(e){
        console.log(e);
    }
    return newLottieJson;

}
Copy the code

Specific use:

    import ResourceLoader from "./r-loader.js";
    import LottieOptionFactory from "./LottieOptionFactory.js";

    / / key global cache resources: string, blobUrl: string; data:Blob,url:string;
     window.GlobCache={};

    let resourcesInfo = [];

    if(window._config){
        // Load the Lottie resource file extracted by lottie-extract-assets-plugin
        resourcesInfo=resourcesInfo.concat(window._config);
    }

    const rl = new ResourceLoader(resourcesInfo, window.idb);

    rl.on("progress".(progress, info) = >{
        console.log("progress:", progress,  info);
        window.GlobCache[info.key]=info;
    });

    rl.on("completed".(datas) = >{
        console.log("Loading completed: completed event:", datas);    
        console.log("total time:".Date.now() - startTime)
    });
 
    rl.reset();
    rl.startLoad();

    // Timeout is used because it takes time to read the cache from indexDB. Production line solution.
     setTimeout(async() = > {const option= await LottieOptionFactory({
            container: document.getElementById('bm'),
            renderer: 'svg'.loop: true.autoplay: true.path : "https://xxx.comacts-effects/luck-draw-act-effect1/data.json"});console.log("option==",option);
        const animation = bodymovin.loadAnimation(option)
    },1000)

Copy the code

Effect:

First load:

Secondary loading:

Lottie final effect

So far, we have achieved Lottie resource loading timing in advance, and used cached resources for multiple loads, successfully reducing network requests.

Application of production line

In the process of applying the production line, we found some areas that could be optimized and made some optimizations to the above logic

  • Use node command (NPM package lottie-extract-assets) to extract resources, no longer use webpack plug-in (save compilation time), support multi-project, multi-directory configuration.
  • The Lottie JSON file is converted into a JSON object in advance. Instead of reading lottieOption when it is created, it is modified to listen for the PROGRESS event of the RLoader and convert Lottie JSON blobUrl directly into a JSON object after reading Lottie JSON blobUrl from the cache.
  • It is not convenient to import the extracted resource file from index.html. You are advised to import lottie-assets.js to index.js.

Some code reference:

startLottieCache.ts

import ResourceLoader from "./r-loader";
import idb from "./idb";


import { fetchResourceJson } from "./cacheUtils";

enum CacheFileType {
    LOTTIE_JSON = "lottie-json-file",
    LOTTIE_IMG = "lottie-img"
}

function parserLottie(globalName: string) {
    const lottieResourcesInfo = [];
    if ((window as any)[globalName]) {
        // Load the Lottie resource file extracted by lottie-extract-assets-plugin
        const lottieConfig = (window as any)[globalName];
        for (let i = 0; i < lottieConfig.length; i++) {
            const item = lottieConfig[i];
            const {
                key, url, source, imgs
            } = item;
            lottieResourcesInfo.push({
                key, url, source, fileType: CacheFileType.LOTTIE_JSON
            });
            lottieResourcesInfo.push(...imgs);
        }
    }
    return lottieResourcesInfo;
}

/** ** Get the Lottie JSON object *@param {any} lottieCacheData
 * @returns* /
function getLottieJson(url) {
    // 2: Access the blob URL of 'data.json' directly to get the JSON object
    return fetchResourceJson(url);
}


export function mergeLottieCache(resourcesInfo = [], globalName) {
    let curResourcesInfo = [...resourcesInfo];
    const lottieResourcesInfo = parserLottie(globalName);
    curResourcesInfo = resourcesInfo.concat(lottieResourcesInfo);
    return curResourcesInfo;
}
/** ** key, cache read after, special processing */
function handleCacheResult(info) {
    if(! info.fileType)return;
    if (info.blobUrl) {
        getLottieJson(info.blobUrl).then((data) = > {
            console.log("data==", data);
            (window as any).GlobCache[info.key].lottieJson = data;
        }).catch((e) = > {
            console.log("Parsing failed", e); }); }}/** ** Enable caching */
export function startCache(resourcesInfo) {(window as any).GlobCache = {};
    const curResourcesInfo = [...resourcesInfo];
    const startTime = Date.now();
    const rl = new ResourceLoader(curResourcesInfo, idb);
    rl.on("progress".(progress, info) = > {
        console.log("progress:", progress, info);
        (window as any).GlobCache[info.key] = info;
        // Key, can be handled for special cache
        handleCacheResult(info);
    });

    rl.reset();
    rl.startLoad();
}

Copy the code

Access:

  1. index.js

       // Import the generated lottie-assets.js file
       import "./lottie-assets";
       // The name of the cache array to merge and the window object in the generated lottie-assets.js file
      const resources=mergeLottieCache([],"_lottieConfig");
      // Enable caching
      startCache(resources);
    Copy the code
  2. use

     const defaultOptions = {
         loop: false.autoplay: false.path: jsonPath,
         rendererSettings: {
             preserveAspectRatio: "xMidYMid slice",}};// Add a LottieOptionFactory wrapper to the original parameters
     LottieOptionFactory(defaultOptions);
    Copy the code

After the language

DEMO code stamp me

Ps :(after the idea of replacing Lottie pictures is realized, we can use the same Lottie in the future to dynamically replace the pictures in json and achieve some customized animation effects. For example: business card display, business card is a Lottie dynamic effect, user avatar is customized, we can ask the designer to design the default user avatar into Lottie animation, dynamic replacement of user avatar)

This article focuses on technical implementation ideas, provided indexDB is supported. Welcome to the community of small partners more comments.