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:
|
||||
css: /assets/lib/bootstrap/bootstrap.min.css
|
||||
js: /assets/lib/bootstrap/bootstrap.bundle.min.js
|
||||
|
||||
toc:
|
||||
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:
|
||||
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:
|
||||
css: https://cdn.jsdelivr.net/npm/tocbot@4.25.0/dist/tocbot.min.css
|
||||
|
|
|
@ -2,9 +2,7 @@
|
|||
|
||||
<!-- commons -->
|
||||
|
||||
{%- capture urls -%}
|
||||
{{ site.data.origin[type].bootstrap.js }},{{ site.data.origin[type].search.js }}
|
||||
{%- endcapture -%}
|
||||
{% assign urls = site.data.origin[type].search.js %}
|
||||
|
||||
<!-- layout specified -->
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
/**
|
||||
* Tab 'Categories' expand/close effect.
|
||||
*/
|
||||
|
||||
import 'bootstrap/js/src/collapse.js';
|
||||
|
||||
const childPrefix = 'l_';
|
||||
const parentPrefix = 'h_';
|
||||
const children = document.getElementsByClassName('collapse');
|
||||
|
|
|
@ -2,10 +2,11 @@
|
|||
* Clipboard functions
|
||||
*
|
||||
* 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 ICON_DEFAULT = 'far fa-clipboard';
|
||||
|
@ -38,11 +39,11 @@ function unlock(node) {
|
|||
function showTooltip(btn) {
|
||||
const succeedTitle = btn.getAttribute(ATTR_TITLE_SUCCEED);
|
||||
btn.setAttribute(ATTR_TITLE_ORIGIN, succeedTitle);
|
||||
bootstrap.Tooltip.getInstance(btn).show();
|
||||
Tooltip.getInstance(btn).show();
|
||||
}
|
||||
|
||||
function hideTooltip(btn) {
|
||||
bootstrap.Tooltip.getInstance(btn).hide();
|
||||
Tooltip.getInstance(btn).hide();
|
||||
btn.removeAttribute(ATTR_TITLE_ORIGIN);
|
||||
}
|
||||
|
||||
|
@ -56,7 +57,7 @@ function resumeIcon(btn) {
|
|||
icon.setAttribute('class', ICON_DEFAULT);
|
||||
}
|
||||
|
||||
export function initClipboard() {
|
||||
function setCodeClipboard() {
|
||||
const clipboardList = document.querySelectorAll(clipboardSelector);
|
||||
|
||||
if (clipboardList.length === 0) {
|
||||
|
@ -73,7 +74,7 @@ export function initClipboard() {
|
|||
|
||||
[...clipboardList].map(
|
||||
(elem) =>
|
||||
new bootstrap.Tooltip(elem, {
|
||||
new Tooltip(elem, {
|
||||
placement: 'left'
|
||||
})
|
||||
);
|
||||
|
@ -97,11 +98,15 @@ export function initClipboard() {
|
|||
unlock(trigger);
|
||||
}, TIMEOUT);
|
||||
});
|
||||
}
|
||||
|
||||
/* --- Post link sharing --- */
|
||||
|
||||
function setLinkClipboard() {
|
||||
const btnCopyLink = document.getElementById('copy-link');
|
||||
|
||||
if (btnCopyLink === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
btnCopyLink.addEventListener('click', (e) => {
|
||||
const target = e.target;
|
||||
|
||||
|
@ -116,7 +121,7 @@ export function initClipboard() {
|
|||
|
||||
// Switch tooltip title
|
||||
target.setAttribute(ATTR_TITLE_ORIGIN, succeedTitle);
|
||||
bootstrap.Tooltip.getInstance(target).show();
|
||||
Tooltip.getInstance(target).show();
|
||||
|
||||
lock(target);
|
||||
|
||||
|
@ -128,6 +133,11 @@ export function initClipboard() {
|
|||
});
|
||||
|
||||
btnCopyLink.addEventListener('mouseleave', (e) => {
|
||||
bootstrap.Tooltip.getInstance(e.target).hide();
|
||||
Tooltip.getInstance(e.target).hide();
|
||||
});
|
||||
}
|
||||
|
||||
export function initClipboard() {
|
||||
setCodeClipboard();
|
||||
setLinkClipboard();
|
||||
}
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
/**
|
||||
* Initial Bootstrap Tooltip.
|
||||
*/
|
||||
import Tooltip from 'bootstrap/js/src/tooltip';
|
||||
|
||||
export function loadTooptip() {
|
||||
const tooltipTriggerList = document.querySelectorAll(
|
||||
'[data-bs-toggle="tooltip"]'
|
||||
);
|
||||
|
||||
[...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 @@
|
|||
---
|
||||
layout: compress
|
||||
permalink: /assets/js/dist/:basename.min.js
|
||||
---
|
||||
import { pwa, baseurl } from '../../_config.yml';
|
||||
import Toast from 'bootstrap/js/src/toast';
|
||||
|
||||
if ('serviceWorker' in navigator) {
|
||||
const isEnabled = '{{ site.pwa.enabled }}' === 'true';
|
||||
|
||||
if (isEnabled) {
|
||||
const swUrl = '{{ '/sw.min.js' | relative_url }}';
|
||||
if (pwa.enabled) {
|
||||
const swUrl = `${baseurl}/sw.min.js`;
|
||||
const notification = document.getElementById('notification');
|
||||
const btnRefresh = notification.querySelector('.toast-body>button');
|
||||
const popupWindow = bootstrap.Toast.getOrCreateInstance(notification);
|
||||
const popupWindow = Toast.getOrCreateInstance(notification);
|
||||
|
||||
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) {
|
||||
popupWindow.show();
|
||||
}
|
||||
|
@ -32,14 +28,13 @@ if ('serviceWorker' in navigator) {
|
|||
if (registration.waiting) {
|
||||
registration.waiting.postMessage('SKIP_WAITING');
|
||||
}
|
||||
|
||||
popupWindow.hide();
|
||||
});
|
||||
});
|
||||
|
||||
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', () => {
|
||||
if (!refreshing) {
|
||||
window.location.reload();
|
|
@ -1,12 +1,7 @@
|
|||
---
|
||||
layout: compress
|
||||
permalink: /:basename.min.js
|
||||
# PWA service worker
|
||||
---
|
||||
import { baseurl } from '../../_config.yml';
|
||||
|
||||
const swconfUrl = '{{ '/assets/js/data/swconf.js' | relative_url }}';
|
||||
importScripts(`${baseurl}/assets/js/data/swconf.js`);
|
||||
|
||||
importScripts(swconfUrl);
|
||||
const purge = swconf.purge;
|
||||
|
||||
function verifyUrl(url) {
|
||||
|
@ -74,7 +69,7 @@ self.addEventListener('fetch', (event) => {
|
|||
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();
|
||||
|
||||
caches.open(swconf.cacheName).then((cache) => {
|
19
package.json
19
package.json
|
@ -13,12 +13,16 @@
|
|||
},
|
||||
"homepage": "https://github.com/cotes2020/jekyll-theme-chirpy/",
|
||||
"scripts": {
|
||||
"prebuild": "npx rimraf assets/js/dist",
|
||||
"build": "NODE_ENV=production npx rollup -c --bundleConfigAsCjs",
|
||||
"prewatch": "npx rimraf assets/js/dist",
|
||||
"watch": "npx rollup -c --bundleConfigAsCjs -w",
|
||||
"test": "npx stylelint _sass/**/*.scss",
|
||||
"fixlint": "npm run test -- --fix"
|
||||
"build": "npm run build:js",
|
||||
"build:js": "rollup -c --bundleConfigAsCjs --environment BUILD:production",
|
||||
"watch:js": "rollup -c --bundleConfigAsCjs -w",
|
||||
"lint:style": "stylelint _sass/**/*.scss",
|
||||
"lint:fix:style": "npm run lint:style -- --fix",
|
||||
"test": "npm run lint:scss"
|
||||
},
|
||||
"dependencies": {
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"bootstrap": "^5.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.24.4",
|
||||
|
@ -27,13 +31,14 @@
|
|||
"@commitlint/cli": "^19.2.2",
|
||||
"@commitlint/config-conventional": "^19.2.2",
|
||||
"@rollup/plugin-babel": "^6.0.4",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"@rollup/plugin-terser": "^0.4.4",
|
||||
"@rollup/plugin-yaml": "^4.1.2",
|
||||
"@semantic-release/changelog": "^6.0.3",
|
||||
"@semantic-release/exec": "^6.0.3",
|
||||
"@semantic-release/git": "^10.0.1",
|
||||
"conventional-changelog-conventionalcommits": "^7.0.2",
|
||||
"husky": "^9.0.11",
|
||||
"rimraf": "^5.0.5",
|
||||
"rollup": "^4.15.0",
|
||||
"rollup-plugin-license": "^3.3.1",
|
||||
"semantic-release": "^23.0.8",
|
||||
|
|
|
@ -1,23 +1,42 @@
|
|||
import babel from '@rollup/plugin-babel';
|
||||
import terser from '@rollup/plugin-terser';
|
||||
import license from 'rollup-plugin-license';
|
||||
import { nodeResolve } from '@rollup/plugin-node-resolve';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import yaml from '@rollup/plugin-yaml';
|
||||
|
||||
const SRC_DEFAULT = '_javascript';
|
||||
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 {
|
||||
input: [`${SRC_DEFAULT}/${filename}.js`],
|
||||
input: [`${src}/${filename}.js`],
|
||||
output: {
|
||||
file: `${DIST_DEFAULT}/${filename}.min.js`,
|
||||
file: `${dist}/${filename}.min.js`,
|
||||
format: 'iife',
|
||||
name: 'Chirpy',
|
||||
sourcemap: !isProd
|
||||
},
|
||||
watch: {
|
||||
include: `${SRC_DEFAULT}/**`
|
||||
include: `${src}/**`
|
||||
},
|
||||
plugins: [
|
||||
babel({
|
||||
|
@ -25,13 +44,16 @@ function build(filename) {
|
|||
presets: ['@babel/env'],
|
||||
plugins: ['@babel/plugin-transform-class-properties']
|
||||
}),
|
||||
nodeResolve(),
|
||||
yaml(),
|
||||
isProd && commentStyle === 'none' && terser(),
|
||||
license({
|
||||
banner: {
|
||||
commentStyle: 'ignored',
|
||||
content: { file: path.join(__dirname, SRC_DEFAULT, '_copyright') }
|
||||
commentStyle,
|
||||
content: { file: bannerUrl }
|
||||
}
|
||||
}),
|
||||
isProd && terser()
|
||||
isProd && commentStyle !== 'none' && terser()
|
||||
]
|
||||
};
|
||||
}
|
||||
|
@ -42,5 +64,11 @@ export default [
|
|||
build('categories'),
|
||||
build('page'),
|
||||
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