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
+ });
+});