This is an automated email from the ASF dual-hosted git repository.

wangzx pushed a commit to branch gh-pages
in repository https://gitbox.apache.org/repos/asf/echarts-examples.git


The following commit(s) were added to refs/heads/gh-pages by this push:
     new e601162f feat(explore): enable wp img acceleator CDN for zh page
e601162f is described below

commit e601162f27aeb5cffb62ab7b987a2315a56fb559
Author: plainheart <[email protected]>
AuthorDate: Mon Oct 9 01:53:38 2023 +0800

    feat(explore): enable wp img acceleator CDN for zh page
---
 build/copyResource.js       |  70 +++++++++++++++++++---
 src/common/config.js        |   5 ++
 src/common/helper.js        |   4 ++
 src/explore/ExampleCard.vue |  49 ++++++++++++++--
 src/explore/Explore.vue     | 137 ++++++++++++++++++++++++++------------------
 5 files changed, 196 insertions(+), 69 deletions(-)

diff --git a/build/copyResource.js b/build/copyResource.js
index bfa378a4..58196a38 100644
--- a/build/copyResource.js
+++ b/build/copyResource.js
@@ -1,9 +1,11 @@
-const fs = require('fs');
+const fs = require('node:fs');
+const fsp = require('node:fs/promises');
 const fse = require('fs-extra');
 const globby = require('globby');
 const chalk = require('chalk');
-const path = require('path');
-const assert = require('assert');
+const path = require('node:path');
+const assert = require('node:assert');
+const crypto = require('node:crypto');
 
 const argv = require('yargs').argv;
 const projectDir = __dirname;
@@ -69,7 +71,7 @@ function initEnv() {
 }
 
 async function copyResourcesToDest(config) {
-  let basePath = path.resolve(projectDir, '../public');
+  const basePath = path.resolve(projectDir, '../public');
   const filePaths = await globby(
     [
       '**/*',
@@ -84,11 +86,11 @@ async function copyResourcesToDest(config) {
 
   console.log();
 
-  for (let filePath of filePaths) {
+  for (const filePath of filePaths) {
     fse.ensureDirSync(
       path.resolve(config.releaseDestDir, path.dirname(filePath))
     );
-    let destPath = path.resolve(config.releaseDestDir, filePath);
+    const destPath = path.resolve(config.releaseDestDir, filePath);
     fs.copyFileSync(path.resolve(basePath, filePath), destPath);
 
     if (process.stdout.clearLine) {
@@ -100,11 +102,65 @@ async function copyResourcesToDest(config) {
     }
   }
 
+  console.log();
+
+  if (config.envType === 'asf') {
+    const rootDir = path.resolve(__dirname, '../public');
+    const thumbPaths = await globby(
+      ['data/thumb/*', 'data/thumb-*/*', 'data-*/thumb/*', 'data-*/thumb-*/*'],
+      {
+        cwd: rootDir
+      }
+    );
+    // calculate sha512 hash
+    const thumbHashMap = {};
+    console.log(
+      'Calculating sha512 hash for example thumbs...',
+      thumbPaths.length
+    );
+    await Promise.all(
+      thumbPaths.map(async (thumbPath) => {
+        const data = await fsp.readFile(
+          path.resolve(rootDir, thumbPath),
+          'binary'
+        );
+        const sha512 = crypto
+          .createHash('sha512')
+          .update(data)
+          .digest('hex')
+          .slice(0, 8);
+        thumbHashMap[thumbPath] = sha512;
+      })
+    );
+    const thumbHashMapPath = path.resolve(
+      config.releaseDestDir,
+      'thumb-hash.json'
+    );
+    fs.writeFileSync(thumbHashMapPath, JSON.stringify(thumbHashMap), 'utf-8');
+
+    Object.entries(thumbHashMap).forEach(([thumbPath, hash]) => {
+      const extname = path.extname(thumbPath);
+      const hashFileName = thumbPath.replace(
+        new RegExp(extname + '$'),
+        '.' + hash + extname
+      );
+      const destPath = path.resolve(config.releaseDestDir, hashFileName);
+      fse.copyFileSync(path.resolve(basePath, thumbPath), destPath);
+      if (process.stdout.clearLine) {
+        process.stdout.clearLine();
+        process.stdout.cursorTo(0);
+        process.stdout.write(chalk.green(`resource copied to: ${destPath}`));
+      } else {
+        console.log(chalk.green(`resource copied to: ${destPath}`));
+      }
+    });
+  }
+
   console.log('\ncopyResourcesToDest done.');
 }
 
 async function run() {
-  let config = initEnv();
+  const config = initEnv();
   await copyResourcesToDest(config);
 
   console.log('All done.');
diff --git a/src/common/config.js b/src/common/config.js
index 40bf3776..ab20fe27 100644
--- a/src/common/config.js
+++ b/src/common/config.js
@@ -109,6 +109,11 @@ export { URL_PARAMS };
 // https://npm.elemecdn.com/
 export const CDN_ROOT = 'https://fastly.jsdelivr.net/npm/';
 
+// NOTE: can't clear the cache with query string and must change the file name
+export const IMG_ACCELERATOR_CDN = [0, 1, 2, 3].map(
+  (subdomain) => `https://i${subdomain}.wp.com`
+);
+
 export const SCRIPT_URLS = {
   echartsDir: `${CDN_ROOT}echarts@{{version}}`,
   echartsNightlyDir: `${CDN_ROOT}echarts-nightly@{{version}}`,
diff --git a/src/common/helper.js b/src/common/helper.js
index 4836af2e..4309cfbb 100644
--- a/src/common/helper.js
+++ b/src/common/helper.js
@@ -126,3 +126,7 @@ export function isTrustedOpener() {
 export function decodeBase64(str) {
   return decodeURIComponent(escape(window.atob(str)));
 }
+
+export function shouldEnableImgAcceleration() {
+  return store.locale === 'zh' && store.cdnRoot.includes('echarts.apache.org');
+}
diff --git a/src/explore/ExampleCard.vue b/src/explore/ExampleCard.vue
index e94f0b3a..57105245 100644
--- a/src/explore/ExampleCard.vue
+++ b/src/explore/ExampleCard.vue
@@ -28,7 +28,8 @@
 
 <script>
 import { store } from '../common/store';
-import { URL_PARAMS } from '../common/config';
+import { URL_PARAMS, IMG_ACCELERATOR_CDN } from '../common/config';
+import { shouldEnableImgAcceleration } from '../common/helper';
 
 export default {
   props: ['example'],
@@ -68,19 +69,57 @@ export default {
       return './editor.html?' + hash.join('&');
     },
 
-    screenshotURLWithoutExt() {
+    enableImgAcceleration: shouldEnableImgAcceleration,
+
+    imgCDN() {
+      const cdnRoot = store.cdnRoot;
+      const acceleratorCDN =
+        this.enableImgAcceleration &&
+        IMG_ACCELERATOR_CDN[~~(Math.random() * IMG_ACCELERATOR_CDN.length)];
+      return acceleratorCDN
+        ? acceleratorCDN + '/' + cdnRoot.slice(cdnRoot.indexOf('//') + 2)
+        : cdnRoot;
+    },
+
+    exampleThumbBasePath() {
       const example = this.example;
       const themePostfix = this.exampleTheme ? '-' + this.exampleTheme : '';
       const folder = example.isGL ? 'data-gl' : 'data';
-      return `${store.cdnRoot}/${folder}/thumb${themePostfix}/${example.id}`;
+      return `${folder}/thumb${themePostfix}/${example.id}`;
     },
 
     screenshotURLWebP() {
-      return this.screenshotURLWithoutExt + `.webp?_v_=${store.version}`;
+      return this.getExampleThumbPath(
+        this.exampleThumbBasePath,
+        'webp',
+        this.imgCDN,
+        this.enableImgAcceleration
+      );
     },
 
     screenshotURLPNG() {
-      return this.screenshotURLWithoutExt + `.png?_v_=${store.version}`;
+      return this.getExampleThumbPath(
+        this.exampleThumbBasePath,
+        'png',
+        this.imgCDN,
+        this.enableImgAcceleration
+      );
+    }
+  },
+
+  methods: {
+    getExampleThumbPath(
+      thumbPathSegment,
+      imgExt,
+      imgCDN,
+      enableImgAcceleration
+    ) {
+      const hash =
+        enableImgAcceleration &&
+        (window.ec_thumb_hash || {})[thumbPathSegment + '.' + imgExt];
+      return `${imgCDN}/${thumbPathSegment}${
+        hash ? '.' + hash : ''
+      }.${imgExt}?_v_=${store.version}`;
     }
   }
 };
diff --git a/src/explore/Explore.vue b/src/explore/Explore.vue
index 89098bf5..f397a521 100644
--- a/src/explore/Explore.vue
+++ b/src/explore/Explore.vue
@@ -68,6 +68,7 @@ import CHART_LIST from '../data/chart-list-data';
 import CHART_LIST_GL from '../data/chart-list-data-gl';
 import { EXAMPLE_CATEGORIES, BLACK_MAP } from '../common/config';
 import { store } from '../common/store';
+import { shouldEnableImgAcceleration } from '../common/helper';
 import ExampleCard from './ExampleCard.vue';
 import LazyLoad from 'vanilla-lazyload/dist/lazyload.esm';
 
@@ -133,46 +134,6 @@ export default {
   data() {
     const exampleListByCategory = {};
 
-    function addExamples(list, isGL) {
-      let categoryOrder = 0;
-      // Add by category order in each example.
-      do {
-        let added = false;
-        for (let i = 0; i < list.length; i++) {
-          const example = list[i];
-          if (BLACK_MAP.hasOwnProperty(example.id)) {
-            continue;
-          }
-          if (typeof example.category === 'string') {
-            example.category = [example.category];
-          }
-
-          const categoryStr = (example.category || [])[categoryOrder];
-          if (categoryStr) {
-            added = true;
-            let categoryObj = exampleListByCategory[categoryStr];
-            if (!categoryObj) {
-              categoryObj = {
-                category: categoryStr,
-                examples: []
-              };
-              exampleListByCategory[categoryStr] = categoryObj;
-            }
-            example.isGL = isGL;
-
-            categoryObj.examples.push(example);
-          }
-        }
-
-        if (!added) {
-          break;
-        }
-      } while (++categoryOrder && categoryOrder < 4); // At most 4 category
-    }
-
-    addExamples(CHART_LIST, false);
-    addExamples(CHART_LIST_GL, true);
-
     return {
       shared: store,
 
@@ -202,7 +163,7 @@ export default {
   computed: {
     exampleList() {
       const list = [];
-      for (let i = 0; i < EXAMPLE_CATEGORIES.length; i++) {
+      for (let i = 0, len = EXAMPLE_CATEGORIES.length; i < len; i++) {
         const category = EXAMPLE_CATEGORIES[i];
         const categoryObj = this.exampleListByCategory[category];
         if (categoryObj && categoryObj.examples.length > 0) {
@@ -217,25 +178,87 @@ export default {
   },
 
   mounted() {
-    window.addEventListener('hashchange', this.onHashChange);
-
-    this._lazyload = new LazyLoad({
-      // Container should be the scroll viewport.
-      // container: this.$el.querySelector('#explore-container 
.example-list-panel'),
-      elements_selector: '.chart-area',
-      load_delay: 400,
-      class_loaded: LAZY_LOADED_CLASS,
-      callback_error(img) {
-        const fallbackSrc = img.src;
-        const children = img.parentElement.children;
-        for (let i = 0, len = children.length; i < len; i++) {
-          const el = children[i];
-          if (el !== img) {
-            el.srcset = fallbackSrc;
+    const exampleListByCategory = {};
+
+    function addExamples(list, isGL) {
+      let categoryOrder = 0;
+      // Add by category order in each example.
+      do {
+        let added = false;
+        for (let i = 0; i < list.length; i++) {
+          const example = list[i];
+          if (BLACK_MAP.hasOwnProperty(example.id)) {
+            continue;
+          }
+          if (typeof example.category === 'string') {
+            example.category = [example.category];
           }
+
+          const categoryStr = (example.category || [])[categoryOrder];
+          if (categoryStr) {
+            added = true;
+            let categoryObj = exampleListByCategory[categoryStr];
+            if (!categoryObj) {
+              categoryObj = {
+                category: categoryStr,
+                examples: []
+              };
+              exampleListByCategory[categoryStr] = categoryObj;
+            }
+            example.isGL = isGL;
+
+            categoryObj.examples.push(example);
+          }
+        }
+
+        if (!added) {
+          break;
         }
+      } while (++categoryOrder && categoryOrder < 4); // At most 4 category
+    }
+
+    const onDone = () => {
+      addExamples(CHART_LIST, false);
+      addExamples(CHART_LIST_GL, true);
+
+      this.$set(this, 'exampleListByCategory', exampleListByCategory);
+
+      this.$nextTick(() => {
+        this._lazyload = new LazyLoad({
+          // Container should be the scroll viewport.
+          // container: this.$el.querySelector('#explore-container 
.example-list-panel'),
+          elements_selector: '.chart-area',
+          load_delay: 400,
+          class_loaded: LAZY_LOADED_CLASS,
+          callback_error(img) {
+            const fallbackSrc = img.src;
+            const children = img.parentElement.children;
+            for (let i = 0, len = children.length; i < len; i++) {
+              const el = children[i];
+              if (el !== img) {
+                el.srcset = fallbackSrc;
+              }
+            }
+          }
+        });
+
+        setTimeout(() => {
+          this.onHashChange();
+          window.addEventListener('hashchange', this.onHashChange);
+        }, 0);
+      });
+    };
+
+    if (!shouldEnableImgAcceleration()) {
+      return onDone();
+    }
+
+    $.getJSON(`${store.cdnRoot}/thumb-hash.json?_v_=${store.version}`).always(
+      (data) => {
+        window.ec_thumb_hash = data;
+        onDone();
       }
-    });
+    );
   },
 
   methods: {


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to