perf: lean bootstrap javascript (#1734)
This commit is contained in:
parent
c17fba44f5
commit
ddb48eda52
11 changed files with 89 additions and 55 deletions
|
@ -6,7 +6,6 @@ webfonts: /assets/lib/fonts/main.css
|
||||||
|
|
||||||
bootstrap:
|
bootstrap:
|
||||||
css: /assets/lib/bootstrap/bootstrap.min.css
|
css: /assets/lib/bootstrap/bootstrap.min.css
|
||||||
js: /assets/lib/bootstrap/bootstrap.bundle.min.js
|
|
||||||
|
|
||||||
toc:
|
toc:
|
||||||
css: /assets/lib/tocbot/tocbot.min.css
|
css: /assets/lib/tocbot/tocbot.min.css
|
||||||
|
|
|
@ -21,7 +21,6 @@ webfonts: https://fonts.googleapis.com/css2?family=Lato:wght@300;400&family=Sour
|
||||||
|
|
||||||
bootstrap:
|
bootstrap:
|
||||||
css: https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css
|
css: https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css
|
||||||
js: https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js
|
|
||||||
|
|
||||||
toc:
|
toc:
|
||||||
css: https://cdn.jsdelivr.net/npm/tocbot@4.25.0/dist/tocbot.min.css
|
css: https://cdn.jsdelivr.net/npm/tocbot@4.25.0/dist/tocbot.min.css
|
||||||
|
|
|
@ -2,9 +2,7 @@
|
||||||
|
|
||||||
<!-- commons -->
|
<!-- commons -->
|
||||||
|
|
||||||
{%- capture urls -%}
|
{% assign urls = site.data.origin[type].search.js %}
|
||||||
{{ site.data.origin[type].bootstrap.js }},{{ site.data.origin[type].search.js }}
|
|
||||||
{%- endcapture -%}
|
|
||||||
|
|
||||||
<!-- layout specified -->
|
<!-- layout specified -->
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
/**
|
/**
|
||||||
* Tab 'Categories' expand/close effect.
|
* Tab 'Categories' expand/close effect.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import 'bootstrap/js/src/collapse.js';
|
||||||
|
|
||||||
const childPrefix = 'l_';
|
const childPrefix = 'l_';
|
||||||
const parentPrefix = 'h_';
|
const parentPrefix = 'h_';
|
||||||
const children = document.getElementsByClassName('collapse');
|
const children = document.getElementsByClassName('collapse');
|
||||||
|
|
|
@ -2,10 +2,11 @@
|
||||||
* Clipboard functions
|
* Clipboard functions
|
||||||
*
|
*
|
||||||
* Dependencies:
|
* Dependencies:
|
||||||
* - popper.js (https://github.com/popperjs/popper-core)
|
* clipboard.js (https://github.com/zenorocha/clipboard.js)
|
||||||
* - clipboard.js (https://github.com/zenorocha/clipboard.js)
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import Tooltip from 'bootstrap/js/src/tooltip';
|
||||||
|
|
||||||
const clipboardSelector = '.code-header>button';
|
const clipboardSelector = '.code-header>button';
|
||||||
|
|
||||||
const ICON_DEFAULT = 'far fa-clipboard';
|
const ICON_DEFAULT = 'far fa-clipboard';
|
||||||
|
@ -38,11 +39,11 @@ function unlock(node) {
|
||||||
function showTooltip(btn) {
|
function showTooltip(btn) {
|
||||||
const succeedTitle = btn.getAttribute(ATTR_TITLE_SUCCEED);
|
const succeedTitle = btn.getAttribute(ATTR_TITLE_SUCCEED);
|
||||||
btn.setAttribute(ATTR_TITLE_ORIGIN, succeedTitle);
|
btn.setAttribute(ATTR_TITLE_ORIGIN, succeedTitle);
|
||||||
bootstrap.Tooltip.getInstance(btn).show();
|
Tooltip.getInstance(btn).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideTooltip(btn) {
|
function hideTooltip(btn) {
|
||||||
bootstrap.Tooltip.getInstance(btn).hide();
|
Tooltip.getInstance(btn).hide();
|
||||||
btn.removeAttribute(ATTR_TITLE_ORIGIN);
|
btn.removeAttribute(ATTR_TITLE_ORIGIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +57,7 @@ function resumeIcon(btn) {
|
||||||
icon.setAttribute('class', ICON_DEFAULT);
|
icon.setAttribute('class', ICON_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initClipboard() {
|
function setCodeClipboard() {
|
||||||
const clipboardList = document.querySelectorAll(clipboardSelector);
|
const clipboardList = document.querySelectorAll(clipboardSelector);
|
||||||
|
|
||||||
if (clipboardList.length === 0) {
|
if (clipboardList.length === 0) {
|
||||||
|
@ -73,7 +74,7 @@ export function initClipboard() {
|
||||||
|
|
||||||
[...clipboardList].map(
|
[...clipboardList].map(
|
||||||
(elem) =>
|
(elem) =>
|
||||||
new bootstrap.Tooltip(elem, {
|
new Tooltip(elem, {
|
||||||
placement: 'left'
|
placement: 'left'
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@ -97,11 +98,15 @@ export function initClipboard() {
|
||||||
unlock(trigger);
|
unlock(trigger);
|
||||||
}, TIMEOUT);
|
}, TIMEOUT);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/* --- Post link sharing --- */
|
function setLinkClipboard() {
|
||||||
|
|
||||||
const btnCopyLink = document.getElementById('copy-link');
|
const btnCopyLink = document.getElementById('copy-link');
|
||||||
|
|
||||||
|
if (btnCopyLink === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
btnCopyLink.addEventListener('click', (e) => {
|
btnCopyLink.addEventListener('click', (e) => {
|
||||||
const target = e.target;
|
const target = e.target;
|
||||||
|
|
||||||
|
@ -116,7 +121,7 @@ export function initClipboard() {
|
||||||
|
|
||||||
// Switch tooltip title
|
// Switch tooltip title
|
||||||
target.setAttribute(ATTR_TITLE_ORIGIN, succeedTitle);
|
target.setAttribute(ATTR_TITLE_ORIGIN, succeedTitle);
|
||||||
bootstrap.Tooltip.getInstance(target).show();
|
Tooltip.getInstance(target).show();
|
||||||
|
|
||||||
lock(target);
|
lock(target);
|
||||||
|
|
||||||
|
@ -128,6 +133,11 @@ export function initClipboard() {
|
||||||
});
|
});
|
||||||
|
|
||||||
btnCopyLink.addEventListener('mouseleave', (e) => {
|
btnCopyLink.addEventListener('mouseleave', (e) => {
|
||||||
bootstrap.Tooltip.getInstance(e.target).hide();
|
Tooltip.getInstance(e.target).hide();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function initClipboard() {
|
||||||
|
setCodeClipboard();
|
||||||
|
setLinkClipboard();
|
||||||
|
}
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
/**
|
import Tooltip from 'bootstrap/js/src/tooltip';
|
||||||
* Initial Bootstrap Tooltip.
|
|
||||||
*/
|
|
||||||
export function loadTooptip() {
|
export function loadTooptip() {
|
||||||
const tooltipTriggerList = document.querySelectorAll(
|
const tooltipTriggerList = document.querySelectorAll(
|
||||||
'[data-bs-toggle="tooltip"]'
|
'[data-bs-toggle="tooltip"]'
|
||||||
);
|
);
|
||||||
|
|
||||||
[...tooltipTriggerList].map(
|
[...tooltipTriggerList].map(
|
||||||
(tooltipTriggerEl) => new bootstrap.Tooltip(tooltipTriggerEl)
|
(tooltipTriggerEl) => new Tooltip(tooltipTriggerEl)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
3
_javascript/pwa/_frontmatter
Normal file
3
_javascript/pwa/_frontmatter
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
permalink: /:basename
|
||||||
|
---
|
|
@ -1,19 +1,15 @@
|
||||||
---
|
import { pwa, baseurl } from '../../_config.yml';
|
||||||
layout: compress
|
import Toast from 'bootstrap/js/src/toast';
|
||||||
permalink: /assets/js/dist/:basename.min.js
|
|
||||||
---
|
|
||||||
|
|
||||||
if ('serviceWorker' in navigator) {
|
if ('serviceWorker' in navigator) {
|
||||||
const isEnabled = '{{ site.pwa.enabled }}' === 'true';
|
if (pwa.enabled) {
|
||||||
|
const swUrl = `${baseurl}/sw.min.js`;
|
||||||
if (isEnabled) {
|
|
||||||
const swUrl = '{{ '/sw.min.js' | relative_url }}';
|
|
||||||
const notification = document.getElementById('notification');
|
const notification = document.getElementById('notification');
|
||||||
const btnRefresh = notification.querySelector('.toast-body>button');
|
const btnRefresh = notification.querySelector('.toast-body>button');
|
||||||
const popupWindow = bootstrap.Toast.getOrCreateInstance(notification);
|
const popupWindow = Toast.getOrCreateInstance(notification);
|
||||||
|
|
||||||
navigator.serviceWorker.register(swUrl).then((registration) => {
|
navigator.serviceWorker.register(swUrl).then((registration) => {
|
||||||
{% comment %}In case the user ignores the notification{% endcomment %}
|
// In case the user ignores the notification
|
||||||
if (registration.waiting) {
|
if (registration.waiting) {
|
||||||
popupWindow.show();
|
popupWindow.show();
|
||||||
}
|
}
|
||||||
|
@ -32,14 +28,13 @@ if ('serviceWorker' in navigator) {
|
||||||
if (registration.waiting) {
|
if (registration.waiting) {
|
||||||
registration.waiting.postMessage('SKIP_WAITING');
|
registration.waiting.postMessage('SKIP_WAITING');
|
||||||
}
|
}
|
||||||
|
|
||||||
popupWindow.hide();
|
popupWindow.hide();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
let refreshing = false;
|
let refreshing = false;
|
||||||
|
|
||||||
{% comment %}Detect controller change and refresh all the opened tabs{% endcomment %}
|
// Detect controller change and refresh all the opened tabs
|
||||||
navigator.serviceWorker.addEventListener('controllerchange', () => {
|
navigator.serviceWorker.addEventListener('controllerchange', () => {
|
||||||
if (!refreshing) {
|
if (!refreshing) {
|
||||||
window.location.reload();
|
window.location.reload();
|
|
@ -1,12 +1,7 @@
|
||||||
---
|
import { baseurl } from '../../_config.yml';
|
||||||
layout: compress
|
|
||||||
permalink: /:basename.min.js
|
|
||||||
# PWA service worker
|
|
||||||
---
|
|
||||||
|
|
||||||
const swconfUrl = '{{ '/assets/js/data/swconf.js' | relative_url }}';
|
importScripts(`${baseurl}/assets/js/data/swconf.js`);
|
||||||
|
|
||||||
importScripts(swconfUrl);
|
|
||||||
const purge = swconf.purge;
|
const purge = swconf.purge;
|
||||||
|
|
||||||
function verifyUrl(url) {
|
function verifyUrl(url) {
|
||||||
|
@ -74,7 +69,7 @@ self.addEventListener('fetch', (event) => {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
{% comment %}See: <https://developers.google.com/web/fundamentals/primers/service-workers#cache_and_return_requests>{% endcomment %}
|
// See: <https://developers.google.com/web/fundamentals/primers/service-workers#cache_and_return_requests>
|
||||||
let responseToCache = response.clone();
|
let responseToCache = response.clone();
|
||||||
|
|
||||||
caches.open(swconf.cacheName).then((cache) => {
|
caches.open(swconf.cacheName).then((cache) => {
|
19
package.json
19
package.json
|
@ -13,12 +13,16 @@
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/cotes2020/jekyll-theme-chirpy/",
|
"homepage": "https://github.com/cotes2020/jekyll-theme-chirpy/",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prebuild": "npx rimraf assets/js/dist",
|
"build": "npm run build:js",
|
||||||
"build": "NODE_ENV=production npx rollup -c --bundleConfigAsCjs",
|
"build:js": "rollup -c --bundleConfigAsCjs --environment BUILD:production",
|
||||||
"prewatch": "npx rimraf assets/js/dist",
|
"watch:js": "rollup -c --bundleConfigAsCjs -w",
|
||||||
"watch": "npx rollup -c --bundleConfigAsCjs -w",
|
"lint:style": "stylelint _sass/**/*.scss",
|
||||||
"test": "npx stylelint _sass/**/*.scss",
|
"lint:fix:style": "npm run lint:style -- --fix",
|
||||||
"fixlint": "npm run test -- --fix"
|
"test": "npm run lint:scss"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@popperjs/core": "^2.11.8",
|
||||||
|
"bootstrap": "^5.3.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.24.4",
|
"@babel/core": "^7.24.4",
|
||||||
|
@ -27,13 +31,14 @@
|
||||||
"@commitlint/cli": "^19.2.2",
|
"@commitlint/cli": "^19.2.2",
|
||||||
"@commitlint/config-conventional": "^19.2.2",
|
"@commitlint/config-conventional": "^19.2.2",
|
||||||
"@rollup/plugin-babel": "^6.0.4",
|
"@rollup/plugin-babel": "^6.0.4",
|
||||||
|
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||||
"@rollup/plugin-terser": "^0.4.4",
|
"@rollup/plugin-terser": "^0.4.4",
|
||||||
|
"@rollup/plugin-yaml": "^4.1.2",
|
||||||
"@semantic-release/changelog": "^6.0.3",
|
"@semantic-release/changelog": "^6.0.3",
|
||||||
"@semantic-release/exec": "^6.0.3",
|
"@semantic-release/exec": "^6.0.3",
|
||||||
"@semantic-release/git": "^10.0.1",
|
"@semantic-release/git": "^10.0.1",
|
||||||
"conventional-changelog-conventionalcommits": "^7.0.2",
|
"conventional-changelog-conventionalcommits": "^7.0.2",
|
||||||
"husky": "^9.0.11",
|
"husky": "^9.0.11",
|
||||||
"rimraf": "^5.0.5",
|
|
||||||
"rollup": "^4.15.0",
|
"rollup": "^4.15.0",
|
||||||
"rollup-plugin-license": "^3.3.1",
|
"rollup-plugin-license": "^3.3.1",
|
||||||
"semantic-release": "^23.0.8",
|
"semantic-release": "^23.0.8",
|
||||||
|
|
|
@ -1,23 +1,42 @@
|
||||||
import babel from '@rollup/plugin-babel';
|
import babel from '@rollup/plugin-babel';
|
||||||
import terser from '@rollup/plugin-terser';
|
import terser from '@rollup/plugin-terser';
|
||||||
import license from 'rollup-plugin-license';
|
import license from 'rollup-plugin-license';
|
||||||
|
import { nodeResolve } from '@rollup/plugin-node-resolve';
|
||||||
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import yaml from '@rollup/plugin-yaml';
|
||||||
|
|
||||||
const SRC_DEFAULT = '_javascript';
|
const SRC_DEFAULT = '_javascript';
|
||||||
const DIST_DEFAULT = 'assets/js/dist';
|
const DIST_DEFAULT = 'assets/js/dist';
|
||||||
const isProd = process.env.NODE_ENV === 'production';
|
const SRC_PWA = `${SRC_DEFAULT}/pwa`;
|
||||||
|
|
||||||
|
const isProd = process.env.BUILD === 'production';
|
||||||
|
|
||||||
|
if (fs.existsSync(DIST_DEFAULT)) {
|
||||||
|
fs.rm(DIST_DEFAULT, { recursive: true, force: true }, (err) => {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function build(filename, opts = {}) {
|
||||||
|
const src = opts.src || SRC_DEFAULT;
|
||||||
|
const dist = opts.dist || DIST_DEFAULT;
|
||||||
|
const bannerUrl =
|
||||||
|
opts.bannerUrl || path.join(__dirname, SRC_DEFAULT, '_copyright');
|
||||||
|
const commentStyle = opts.commentStyle || 'ignored';
|
||||||
|
|
||||||
function build(filename) {
|
|
||||||
return {
|
return {
|
||||||
input: [`${SRC_DEFAULT}/${filename}.js`],
|
input: [`${src}/${filename}.js`],
|
||||||
output: {
|
output: {
|
||||||
file: `${DIST_DEFAULT}/${filename}.min.js`,
|
file: `${dist}/${filename}.min.js`,
|
||||||
format: 'iife',
|
format: 'iife',
|
||||||
name: 'Chirpy',
|
name: 'Chirpy',
|
||||||
sourcemap: !isProd
|
sourcemap: !isProd
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
include: `${SRC_DEFAULT}/**`
|
include: `${src}/**`
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
babel({
|
babel({
|
||||||
|
@ -25,13 +44,16 @@ function build(filename) {
|
||||||
presets: ['@babel/env'],
|
presets: ['@babel/env'],
|
||||||
plugins: ['@babel/plugin-transform-class-properties']
|
plugins: ['@babel/plugin-transform-class-properties']
|
||||||
}),
|
}),
|
||||||
|
nodeResolve(),
|
||||||
|
yaml(),
|
||||||
|
isProd && commentStyle === 'none' && terser(),
|
||||||
license({
|
license({
|
||||||
banner: {
|
banner: {
|
||||||
commentStyle: 'ignored',
|
commentStyle,
|
||||||
content: { file: path.join(__dirname, SRC_DEFAULT, '_copyright') }
|
content: { file: bannerUrl }
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
isProd && terser()
|
isProd && commentStyle !== 'none' && terser()
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -42,5 +64,11 @@ export default [
|
||||||
build('categories'),
|
build('categories'),
|
||||||
build('page'),
|
build('page'),
|
||||||
build('post'),
|
build('post'),
|
||||||
build('misc')
|
build('misc'),
|
||||||
|
build('app', { src: SRC_PWA }),
|
||||||
|
build('sw', {
|
||||||
|
src: SRC_PWA,
|
||||||
|
bannerUrl: path.join(__dirname, SRC_PWA, '_frontmatter'),
|
||||||
|
commentStyle: 'none'
|
||||||
|
})
|
||||||
];
|
];
|
||||||
|
|
Loading…
Reference in a new issue