├── .editorconfig ├── .env.exaample ├── .gitignore ├── .npmrc ├── README.md ├── assets └── demo.gif ├── components ├── TheHeader.vue └── TheNav.vue ├── layouts └── default.vue ├── nuxt.config.js ├── package-lock.json ├── package.json ├── pages ├── help.vue ├── index.vue └── pgp.vue ├── plugins └── guess.js ├── routes.json └── store └── index.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | indent_size = 2 9 | indent_style = space 10 | insert_final_newline = true 11 | trim_trailing_whitespace = true 12 | 13 | [*.md] 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /.env.exaample: -------------------------------------------------------------------------------- 1 | GA=XXXXXXX 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .nuxt 3 | NOTE.md 4 | .env 5 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | @daliborgogic:registry=https://npm.pkg.github.com/ 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Guess.js + Nuxt.js 2 | 3 | **[Guess.js](https://github.com/guess-js/guess) is a collection of libraries & tools for enabling data-driven user-experience on the web.** 4 | 5 | **[Nuxt.js](https://github.com/nuxt/nuxt.js) is a Vue.js Meta Framework to create complex, fast & universal web applications quickly.** 6 | 7 |

8 | 9 |
10 | DEMO 11 |
12 |

13 | 14 | In this particular example, we combine Guess.js with Nuxt.js to introduce predictive prefetching of JavaScript bundles. Based on user navigation patterns collected from Google Analytics or other source, Guess.js builds a machine-learning model to predict and prefetch JavaScript that will be required in each subsequent page. 15 | 16 | Based on early benchmarks, this can improve the perceived page load performance with 20%. 17 | 18 | For more information on Guess.js, take a look at the following links: 19 | * [Google I/O announcement](https://www.youtube.com/watch?time_continue=2093&v=Mv-l3-tJgGk) by Addy Osmani 20 | * [Introducing Guess.js - a toolkit for enabling data-driven user-experiences on the Web](https://blog.mgechev.com/2018/05/09/introducing-guess-js-data-driven-user-experiences-web/) 21 | * [Using Guess.js with static sites](https://github.com/guess-js/guess/tree/master/experiments/guess-static-sites) 22 | * [Using Guess.js with Angular, React, and Gatsby](https://github.com/guess-js/guess/tree/master/packages/guess-webpack) 23 | 24 | ### Usage 25 | 26 | ```bash 27 | $ git clone git@github.com:daliborgogic/guess-nuxt && \ 28 | cd guess-nuxt && \ 29 | npm i 30 | 31 | $ mv .env.example .env 32 | # Update GA in .env 33 | 34 | # Dev 35 | $ npm run dev 36 | 37 | # Build 38 | $ npm run build 39 | 40 | # Start 41 | $ npm start 42 | ``` 43 | 44 | ### Integration 45 | 46 | Guess.js (**0.1.5 and above**) works with Nuxt.js with only two points of integration. All you need to do is add the `GuessPlugin` to `nuxt.config.js` and introduce a snippet for prefetching the pages which are likely to be visited Nuxt. 47 | 48 | The following sections describe both points in details. 49 | 50 | ### Webpack Config 51 | 52 | All you need is to extend the webpack config of your Nuxt.js application is to add the `GuessPlugin` to `nuxt.config.js` file, located in the root of your project. If the file does not exist, create it and add the following content: 53 | 54 | ```javascript 55 | const { GuessPlugin } = require('guess-webpack') 56 | const { GA } = process.env 57 | 58 | module.exports = { 59 | build: { 60 | extend(config, ctx) { 61 | if (ctx.isClient) { 62 | config.plugins.push( 63 | new GuessPlugin({ 64 | GA, 65 | runtime: { 66 | delegate: true 67 | }, 68 | routeProvider: false 69 | }) 70 | ) 71 | } 72 | } 73 | } 74 | ``` 75 | 76 | The routes that `guess()` returns depend on the Google Analytics report that it has extracted, together with the user's effective connection type. 77 | 78 | ### Credits 79 | 80 | Based on [guess-next](https://github.com/mgechev/guess-next) by Minko Gechev [mgechev](https://github.com/mgechev) and Sébastien Chopin [Atinux](https://github.com/Atinux) for pull request [#1](https://github.com/daliborgogic/guess-nuxt/pull/1). 81 | 82 | ### License 83 | 84 | MIT 85 | -------------------------------------------------------------------------------- /assets/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daliborgogic/guess-nuxt/2315d497a1443e35994326310cdfcd2163ba9c3d/assets/demo.gif -------------------------------------------------------------------------------- /components/TheHeader.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 27 | -------------------------------------------------------------------------------- /components/TheNav.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 25 | -------------------------------------------------------------------------------- /layouts/default.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | 15 | 52 | -------------------------------------------------------------------------------- /nuxt.config.js: -------------------------------------------------------------------------------- 1 | import { guess } from 'guess-webpack/api'; 2 | 3 | const { GuessPlugin } = require('guess-webpack') 4 | const { GA } = process.env 5 | 6 | export default { 7 | head: { 8 | htmlAttrs: { 9 | lang: 'en', 10 | }, 11 | meta: [ 12 | { charset: 'utf-8' }, 13 | { name: 'viewport', content: 'width=device-width, initial-scale=1' }, 14 | { hid: 'description', name: 'description', content: 'Experiment for integration of Guess.js with Nuxt.js' } 15 | ] 16 | }, 17 | 18 | plugins: [ 19 | { src: '~/plugins/guess', ssr: false } 20 | ], 21 | 22 | build: { 23 | extend(config, ctx) { 24 | if (ctx.isClient) { 25 | const guessOptions = { 26 | // Hints Guess to not perform pre-fetching and delegate this logic to its consumer. 27 | runtime: { 28 | delegate: true, 29 | prefetchConfig: { 30 | '4g': 0.3, 31 | '3g': 0.3, 32 | '2g': 0.3, 33 | 'slow-2g': 0.3 34 | } 35 | }, 36 | // Guess does not have to collect the routes and the corresponding bundle entry points. 37 | routeProvider: false 38 | } 39 | if (GA) guessOptions.GA = GA 40 | else guessOptions.reportProvider = () => Promise.resolve(JSON.parse(require('fs').readFileSync('./routes.json'))); 41 | 42 | config.plugins.push( 43 | new GuessPlugin(guessOptions) 44 | ) 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@daliborgogic/guess-nuxt", 3 | "version": "1.0.0", 4 | "description": "Guess.js with Nuxt.js", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "nuxt", 8 | "build": "nuxt build", 9 | "start": "nuxt-start" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/daliborgogic/guess-nuxt.git" 14 | }, 15 | "keywords": [], 16 | "author": "", 17 | "license": "MIT", 18 | "bugs": { 19 | "url": "https://github.com/daliborgogic/guess-nuxt/issues" 20 | }, 21 | "homepage": "https://github.com/daliborgogic/guess-nuxt#readme", 22 | "dependencies": { 23 | "nuxt-start-edge": "^2.0.0-25603961.baaf67d" 24 | }, 25 | "devDependencies": { 26 | "guess-webpack": "^0.1.5", 27 | "nuxt-edge": "^2.0.0-25603961.baaf67d", 28 | "pug": "^2.0.3", 29 | "pug-plain-loader": "^1.0.0", 30 | "stylus": "^0.54.5", 31 | "stylus-loader": "^3.0.2" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /pages/help.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 28 | -------------------------------------------------------------------------------- /pages/index.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /pages/pgp.vue: -------------------------------------------------------------------------------- 1 | 57 | 58 | 65 | -------------------------------------------------------------------------------- /plugins/guess.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import { guess } from 'guess-webpack/api' 3 | 4 | export default ({ app: { router, store } }) => { 5 | router.afterEach(to => { 6 | // Wait for page to be displayed 7 | Vue.nextTick(() => { 8 | let predictions = Object.keys(guess()).sort((a, b) => a.probability - b.probability) 9 | predictions.forEach(path => { 10 | router.getMatchedComponents(path).forEach(Component => { 11 | if (typeof Component === 'function') { 12 | try { Component() } catch (e) {} 13 | } 14 | }) 15 | }) 16 | store.commit('setPredictions', predictions) 17 | }) 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /routes.json: -------------------------------------------------------------------------------- 1 | { 2 | "/": { 3 | "/help": 80, 4 | "/pgp": 20 5 | }, 6 | "/help": { 7 | "/": 20, 8 | "/pgp": 80 9 | }, 10 | "/pgp": { 11 | "/": 80, 12 | "/help": 20 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /store/index.js: -------------------------------------------------------------------------------- 1 | import Vuex from 'vuex' 2 | 3 | const store = () => { 4 | return new Vuex.Store({ 5 | state: { 6 | predictions: [] 7 | }, 8 | 9 | mutations: { 10 | setPredictions: (state, value) => state.predictions = value 11 | } 12 | }) 13 | } 14 | 15 | export default store 16 | --------------------------------------------------------------------------------