diff --git a/build/build.js b/build/build.js index 0de786828..483047765 100644 --- a/build/build.js +++ b/build/build.js @@ -1,13 +1,13 @@ -const rollup = require('rollup') -const buble = require('rollup-plugin-buble') -const commonjs = require('rollup-plugin-commonjs') -const nodeResolve = require('rollup-plugin-node-resolve') -const { uglify } = require('rollup-plugin-uglify') -const replace = require('rollup-plugin-replace') -const isProd = process.env.NODE_ENV === 'production' -const version = process.env.VERSION || require('../package.json').version -const chokidar = require('chokidar') -const path = require('path') +const rollup = require('rollup'); +const buble = require('rollup-plugin-buble'); +const commonjs = require('rollup-plugin-commonjs'); +const nodeResolve = require('rollup-plugin-node-resolve'); +const { terser } = require('rollup-plugin-terser'); +const replace = require('rollup-plugin-replace'); +const isProd = process.env.NODE_ENV === 'production'; +const version = process.env.VERSION || require('../package.json').version; +const chokidar = require('chokidar'); +const path = require('path'); /** * @param {{ @@ -24,89 +24,100 @@ async function build(opts) { plugins: (opts.plugins || []).concat([ buble({ transforms: { - dangerousForOf: true - }}), + dangerousForOf: true, + }, + }), commonjs(), nodeResolve(), replace({ __VERSION__: version, - 'process.env.SSR': false - }) + 'process.env.SSR': false, + }), ]), onwarn: function (message) { if (message.code === 'UNRESOLVED_IMPORT') { throw new Error( `Could not resolve module ` + - message.source + - `. Try running 'npm install' or using rollup's 'external' option if this is an external dependency. ` + - `Module ${message.source} is imported in ${message.importer}` - ) + message.source + + `. Try running 'npm install' or using rollup's 'external' option if this is an external dependency. ` + + `Module ${message.source} is imported in ${message.importer}` + ); } - } + }, }) .then(function (bundle) { - var dest = 'lib/' + (opts.output || opts.input) + var dest = 'lib/' + (opts.output || opts.input); - console.log(dest) + console.log(dest); return bundle.write({ format: 'iife', - output: opts.globalName ? {name: opts.globalName} : {}, + output: { + name: opts.globalName || null, + file: dest, + }, file: dest, - strict: false - }) - }) + strict: false, + }); + }); } async function buildCore() { - const promises = [] + const promises = []; - promises.push(build({ - input: 'src/core/index.js', - output: 'docsify.js', - })) + promises.push( + build({ + input: 'src/core/index.js', + output: 'docsify.js', + }) + ); if (isProd) { - promises.push(build({ - input: 'src/core/index.js', - output: 'docsify.min.js', - plugins: [uglify()] - })) + promises.push( + build({ + input: 'src/core/index.js', + output: 'docsify.min.js', + plugins: [terser()], + }) + ); } - await Promise.all(promises) + await Promise.all(promises); } async function buildAllPlugin() { var plugins = [ - {name: 'search', input: 'search/index.js'}, - {name: 'ga', input: 'ga.js'}, - {name: 'matomo', input: 'matomo.js'}, - {name: 'emoji', input: 'emoji.js'}, - {name: 'external-script', input: 'external-script.js'}, - {name: 'front-matter', input: 'front-matter/index.js'}, - {name: 'zoom-image', input: 'zoom-image.js'}, - {name: 'disqus', input: 'disqus.js'}, - {name: 'gitalk', input: 'gitalk.js'} - ] + { name: 'search', input: 'search/index.js' }, + { name: 'ga', input: 'ga.js' }, + { name: 'gtag', input: 'gtag.js' }, + { name: 'matomo', input: 'matomo.js' }, + { name: 'emoji', input: 'emoji.js' }, + { name: 'external-script', input: 'external-script.js' }, + { name: 'front-matter', input: 'front-matter/index.js' }, + { name: 'zoom-image', input: 'zoom-image.js' }, + { name: 'disqus', input: 'disqus.js' }, + { name: 'gitalk', input: 'gitalk.js' }, + ]; const promises = plugins.map(item => { return build({ input: 'src/plugins/' + item.input, - output: 'plugins/' + item.name + '.js' - }) - }) + output: 'plugins/' + item.name + '.js', + }); + }); if (isProd) { plugins.forEach(item => { - promises.push(build({ - input: 'src/plugins/' + item.input, - output: 'plugins/' + item.name + '.min.js', - plugins: [uglify()] - })) - }) + promises.push( + build({ + input: 'src/plugins/' + item.input, + output: 'plugins/' + item.name + '.min.js', + plugins: [terser()], + }) + ); + }); } - await Promise.all(promises) + await Promise.all(promises); } async function main() { @@ -116,41 +127,37 @@ async function main() { atomic: true, awaitWriteFinish: { stabilityThreshold: 1000, - pollInterval: 100 - } + pollInterval: 100, + }, }) .on('change', p => { - console.log('[watch] ', p) - const dirs = p.split(path.sep) + console.log('[watch] ', p); + const dirs = p.split(path.sep); if (dirs[1] === 'core') { - buildCore() + buildCore(); } else if (dirs[2]) { - const name = path.basename(dirs[2], '.js') + const name = path.basename(dirs[2], '.js'); const input = `src/plugins/${name}${ /\.js/.test(dirs[2]) ? '' : '/index' - }.js` + }.js`; build({ input, - output: 'plugins/' + name + '.js' - }) + output: 'plugins/' + name + '.js', + }); } }) .on('ready', () => { - console.log('[start]') - buildCore() - buildAllPlugin() - }) + console.log('[start]'); + buildCore(); + buildAllPlugin(); + }); } else { - await Promise.all([ - buildCore(), - buildAllPlugin() - ]) + await Promise.all([buildCore(), buildAllPlugin()]); } } -main().catch((e) => { - console.error(e) - process.exit(1) -}) - +main().catch(e => { + console.error(e); + process.exit(1); +}); diff --git a/docs/plugins.md b/docs/plugins.md index 3db7ff56b..dce1f4e64 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -71,6 +71,8 @@ This plugin ignores diacritical marks when performing a full text search (e.g., ## Google Analytics +> Google's Universal Analytics service will no longer process new data in standard properties beginning July 1, 2023. Prepare now by setting up and switching over to a Google Analytics 4 property and docsify's gtag.js plugin. + Install the plugin and configure the track id. ```html @@ -91,6 +93,31 @@ Configure by `data-ga`. ``` +## Google Analytics 4 (GA4) + +Install the plugin and configure the track id. + +```html + + + +``` + ## Emoji Renders a larger collection of emoji shorthand codes. Without this plugin, Docsify is able to render only a limited number of emoji shorthand codes. diff --git a/package-lock.json b/package-lock.json index 2212e07e0..675133849 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,13 +48,13 @@ "npm-run-all": "^4.1.5", "prettier": "^2.5.1", "rimraf": "^3.0.0", - "rollup": "^1.23.1", + "rollup": "^2.77.2", "rollup-plugin-async": "^1.2.0", "rollup-plugin-buble": "^0.19.8", "rollup-plugin-commonjs": "^10.1.0", "rollup-plugin-node-resolve": "^5.2.0", "rollup-plugin-replace": "^2.2.0", - "rollup-plugin-uglify": "^6.0.4", + "rollup-plugin-terser": "^7.0.2", "serve-handler": "^6.1.2", "stylus": "^0.54.5", "vue2": "npm:vue@^2.6.12", @@ -2777,6 +2777,64 @@ "node": ">=8" } }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", + "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@lerna/add": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/@lerna/add/-/add-3.21.0.tgz", @@ -20504,6 +20562,15 @@ "node": ">=8" } }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -21232,23 +21299,24 @@ } }, "node_modules/rollup": { - "version": "1.32.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.32.1.tgz", - "integrity": "sha512-/2HA0Ec70TvQnXdzynFffkjA6XN+1e2pEv/uKS5Ulca40g2L7KuOE3riasHoNVHOsFD5KKZgDsMk1CP3Tw9s+A==", + "version": "2.77.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.77.2.tgz", + "integrity": "sha512-m/4YzYgLcpMQbxX3NmAqDvwLATZzxt8bIegO78FZLl+lAgKJBd1DRAOeEiZcKOIOPjxE6ewHWHNgGEalFXuz1g==", "dev": true, - "dependencies": { - "@types/estree": "*", - "@types/node": "*", - "acorn": "^7.1.0" - }, "bin": { "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" } }, "node_modules/rollup-plugin-async": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/rollup-plugin-async/-/rollup-plugin-async-1.2.0.tgz", - "integrity": "sha1-+V/dKfi28jMrWomp1k7oCHsSskk=", + "integrity": "sha512-5/LCGFDejG5OwfiNp377VqMjLQz87LBs4cXUfNiHHxrwd9RixiGgFDfv/4+KD9eKENr/bmUVwFRgMsL2mJW7Ag==", "dev": true, "dependencies": { "async-to-gen": "^1.2.0", @@ -21365,44 +21433,54 @@ "estree-walker": "^0.6.1" } }, - "node_modules/rollup-plugin-uglify": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/rollup-plugin-uglify/-/rollup-plugin-uglify-6.0.4.tgz", - "integrity": "sha512-ddgqkH02klveu34TF0JqygPwZnsbhHVI6t8+hGTcYHngPkQb5MIHI0XiztXIN/d6V9j+efwHAqEL7LspSxQXGw==", + "node_modules/rollup-plugin-terser": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", + "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.0.0", - "jest-worker": "^24.0.0", - "serialize-javascript": "^2.1.2", - "uglify-js": "^3.4.9" + "@babel/code-frame": "^7.10.4", + "jest-worker": "^26.2.1", + "serialize-javascript": "^4.0.0", + "terser": "^5.0.0" }, "peerDependencies": { - "rollup": ">=0.66.0 <2" + "rollup": "^2.0.0" } }, - "node_modules/rollup-plugin-uglify/node_modules/jest-worker": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", - "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", + "node_modules/rollup-plugin-terser/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/rollup-plugin-terser/node_modules/jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", "dev": true, "dependencies": { + "@types/node": "*", "merge-stream": "^2.0.0", - "supports-color": "^6.1.0" + "supports-color": "^7.0.0" }, "engines": { - "node": ">= 6" + "node": ">= 10.13.0" } }, - "node_modules/rollup-plugin-uglify/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "node_modules/rollup-plugin-terser/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=6" + "node": ">=8" } }, "node_modules/rollup-pluginutils": { @@ -21421,18 +21499,6 @@ "integrity": "sha1-va/oCVOD2EFNXcLs9MkXO225QS4=", "dev": true }, - "node_modules/rollup/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -21658,10 +21724,13 @@ } }, "node_modules/serialize-javascript": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz", - "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==", - "dev": true + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } }, "node_modules/serve-handler": { "version": "6.1.3", @@ -23341,6 +23410,42 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/terser": { + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser/node_modules/acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -23797,6 +23902,7 @@ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.5.tgz", "integrity": "sha512-qZukoSxOG0urUTvjc2ERMTcAy+BiFh3weWAkeurLwjrCba73poHmG3E36XEjd/JGukMzwTL7uCxZiAexj8ppvQ==", "dev": true, + "optional": true, "bin": { "uglifyjs": "bin/uglifyjs" }, @@ -26794,6 +26900,55 @@ } } }, + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true + }, + "@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", + "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "@lerna/add": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/@lerna/add/-/add-3.21.0.tgz", @@ -41052,6 +41207,15 @@ "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", "dev": true }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -41640,28 +41804,18 @@ } }, "rollup": { - "version": "1.32.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.32.1.tgz", - "integrity": "sha512-/2HA0Ec70TvQnXdzynFffkjA6XN+1e2pEv/uKS5Ulca40g2L7KuOE3riasHoNVHOsFD5KKZgDsMk1CP3Tw9s+A==", + "version": "2.77.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.77.2.tgz", + "integrity": "sha512-m/4YzYgLcpMQbxX3NmAqDvwLATZzxt8bIegO78FZLl+lAgKJBd1DRAOeEiZcKOIOPjxE6ewHWHNgGEalFXuz1g==", "dev": true, "requires": { - "@types/estree": "*", - "@types/node": "*", - "acorn": "^7.1.0" - }, - "dependencies": { - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - } + "fsevents": "~2.3.2" } }, "rollup-plugin-async": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/rollup-plugin-async/-/rollup-plugin-async-1.2.0.tgz", - "integrity": "sha1-+V/dKfi28jMrWomp1k7oCHsSskk=", + "integrity": "sha512-5/LCGFDejG5OwfiNp377VqMjLQz87LBs4cXUfNiHHxrwd9RixiGgFDfv/4+KD9eKENr/bmUVwFRgMsL2mJW7Ag==", "dev": true, "requires": { "async-to-gen": "^1.2.0", @@ -41776,35 +41930,42 @@ } } }, - "rollup-plugin-uglify": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/rollup-plugin-uglify/-/rollup-plugin-uglify-6.0.4.tgz", - "integrity": "sha512-ddgqkH02klveu34TF0JqygPwZnsbhHVI6t8+hGTcYHngPkQb5MIHI0XiztXIN/d6V9j+efwHAqEL7LspSxQXGw==", + "rollup-plugin-terser": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", + "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "jest-worker": "^24.0.0", - "serialize-javascript": "^2.1.2", - "uglify-js": "^3.4.9" + "@babel/code-frame": "^7.10.4", + "jest-worker": "^26.2.1", + "serialize-javascript": "^4.0.0", + "terser": "^5.0.0" }, "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, "jest-worker": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", - "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", "dev": true, "requires": { + "@types/node": "*", "merge-stream": "^2.0.0", - "supports-color": "^6.1.0" + "supports-color": "^7.0.0" } }, "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" } } } @@ -42009,10 +42170,13 @@ } }, "serialize-javascript": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz", - "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==", - "dev": true + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } }, "serve-handler": { "version": "6.1.3", @@ -43369,6 +43533,32 @@ } } }, + "terser": { + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", + "dev": true, + "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "dependencies": { + "acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + } + } + }, "test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -43727,7 +43917,8 @@ "version": "3.14.5", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.5.tgz", "integrity": "sha512-qZukoSxOG0urUTvjc2ERMTcAy+BiFh3weWAkeurLwjrCba73poHmG3E36XEjd/JGukMzwTL7uCxZiAexj8ppvQ==", - "dev": true + "dev": true, + "optional": true }, "uid-number": { "version": "0.0.6", diff --git a/package.json b/package.json index bca7700db..5ffac4444 100644 --- a/package.json +++ b/package.json @@ -103,13 +103,13 @@ "npm-run-all": "^4.1.5", "prettier": "^2.5.1", "rimraf": "^3.0.0", - "rollup": "^1.23.1", + "rollup": "^2.77.2", "rollup-plugin-async": "^1.2.0", "rollup-plugin-buble": "^0.19.8", "rollup-plugin-commonjs": "^10.1.0", "rollup-plugin-node-resolve": "^5.2.0", "rollup-plugin-replace": "^2.2.0", - "rollup-plugin-uglify": "^6.0.4", + "rollup-plugin-terser": "^7.0.2", "serve-handler": "^6.1.2", "stylus": "^0.54.5", "vue2": "npm:vue@^2.6.12", diff --git a/src/plugins/gtag.js b/src/plugins/gtag.js new file mode 100644 index 000000000..aec713cb7 --- /dev/null +++ b/src/plugins/gtag.js @@ -0,0 +1,72 @@ +/* eslint-disable no-console */ +// From ./ga.js + +function appendScript(id) { + const script = document.createElement('script'); + script.async = true; + script.src = 'https://www.googletagmanager.com/gtag/js?id=' + id; + document.body.appendChild(script); +} + +// global site tag instance initialized +function initGlobalSiteTag(id) { + appendScript(id); + + window.dataLayer = window.dataLayer || []; + window.gtag = + window.gtag || + function () { + window.dataLayer.push(arguments); + }; + + window.gtag('js', new Date()); + window.gtag('config', id); +} + +// add additional products to your tag +// https://developers.google.com/tag-platform/gtagjs/install +function initAdditionalTag(id) { + window.gtag('config', id); +} + +function init(ids) { + if (Array.isArray(ids)) { + // set the first id to be a global site tag + initGlobalSiteTag(ids[0]); + + // the rest ids + ids.forEach((id, index) => { + if (index > 0) { + initAdditionalTag(id); + } + }); + } else { + initGlobalSiteTag(ids); + } +} + +function collect() { + if (!window.gtag) { + init($docsify.gtag); + } + + // usage: https://developers.google.com/analytics/devguides/collection/gtagjs/pages + window.gtag('event', 'page_view', { + /* eslint-disable camelcase */ + page_title: document.title, + page_location: location.href, + page_path: location.pathname, + /* eslint-disable camelcase */ + }); +} + +const install = function (hook) { + if (!$docsify.gtag) { + console.error('[Docsify] gtag is required.'); + return; + } + + hook.beforeEach(collect); +}; + +$docsify.plugins = [].concat(install, $docsify.plugins); diff --git a/test/e2e/gtag.test.js b/test/e2e/gtag.test.js new file mode 100644 index 000000000..c3ebbcd18 --- /dev/null +++ b/test/e2e/gtag.test.js @@ -0,0 +1,97 @@ +// Modules, constants, and variables +// npm run test:e2e gtag.test.js +// ----------------------------------------------------------------------------- +const docsifyInit = require('../helpers/docsify-init'); +const { test, expect } = require('./fixtures/docsify-init-fixture'); + +const gtagList = [ + 'AW-YYYYYY', // Google Ads + 'DC-ZZZZZZ', // Floodlight + 'G-XXXXXX', // Google Analytics 4 (GA4) + 'UA-XXXXXX', // Google Universal Analytics (GA3) +]; + +// Suite +// ----------------------------------------------------------------------------- +test.describe('Gtag Plugin Tests', () => { + // page request listened, print collect url + function pageRequestListened(page) { + page.on('request', request => { + if (request.url().indexOf('www.google-analytics.com') !== -1) { + // console.log(request.url()); + } + }); + + page.on('response', response => { + const request = response.request(); + // googleads.g.doubleclick.net + // www.google-analytics.com + // www.googletagmanager.com + const reg = + /googleads\.g\.doubleclick\.net|www\.google-analytics\.com|www\.googletagmanager\.com/g; + if (request.url().match(reg)) { + // console.log(request.url(), response.status()); + } + }); + } + + // Tests + // --------------------------------------------------------------------------- + test('single gtag', async ({ page }) => { + pageRequestListened(page); + + const docsifyInitConfig = { + config: { + gtag: gtagList[0], + }, + scriptURLs: ['/lib/plugins/gtag.min.js'], + styleURLs: ['/lib/themes/vue.css'], + }; + + await docsifyInit({ + ...docsifyInitConfig, + }); + + const $docsify = await page.evaluate(() => window.$docsify); + + // Verify config options + expect(typeof $docsify).toEqual('object'); + + // console.log($docsify.gtag, $docsify.gtag === ''); + + // Tests + expect($docsify.gtag).not.toEqual(''); + }); + + test('multi gtag', async ({ page }) => { + pageRequestListened(page); + + const docsifyInitConfig = { + config: { + gtag: gtagList, + }, + scriptURLs: ['/lib/plugins/gtag.min.js'], + styleURLs: ['/lib/themes/vue.css'], + }; + + await docsifyInit({ + ...docsifyInitConfig, + }); + + const $docsify = await page.evaluate(() => window.$docsify); + + // Verify config options + expect(typeof $docsify).toEqual('object'); + + // console.log($docsify.gtag, $docsify.gtag === ''); + + // Tests + expect($docsify.gtag).not.toEqual(''); + }); + + test('data-ga attribute', async ({ page }) => { + pageRequestListened(page); + + // TODO + }); +});