├── .babelrc ├── .editorconfig ├── .eslintrc.js ├── .gitignore ├── .prettierrc ├── LICENSE ├── README.md ├── assets ├── README.md ├── content │ └── items.json └── sass │ ├── main.sass │ └── variables.sass ├── components ├── Item.vue ├── Navbar.vue └── README.md ├── jest.config.js ├── lambdas └── hello.js ├── layouts ├── README.md └── default.vue ├── middleware └── README.md ├── netlify.toml ├── nuxt.config.js ├── package.json ├── pages ├── 404.vue ├── README.md ├── about.vue ├── hello.vue ├── index.vue ├── items │ ├── _id │ │ └── index.vue │ └── index.vue └── lambdas │ ├── hello.vue │ └── index.vue ├── plugins ├── README.md ├── fontawesome.js ├── ga.js ├── hotjar.js ├── jsonld.js └── mailchimp.js ├── static ├── README.md ├── favicon.ico └── robots.txt ├── store └── README.md ├── test └── Logo.spec.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "test": { 4 | "presets": [ 5 | [ 6 | "@babel/preset-env", 7 | { 8 | "targets": { 9 | "node": "current" 10 | } 11 | } 12 | ] 13 | ] 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | browser: true, 5 | node: true 6 | }, 7 | parserOptions: { 8 | parser: 'babel-eslint' 9 | }, 10 | extends: [ 11 | '@nuxtjs', 12 | 'plugin:nuxt/recommended', 13 | 'plugin:prettier/recommended', 14 | 'prettier', 15 | 'prettier/vue' 16 | ], 17 | plugins: [ 18 | 'prettier' 19 | ], 20 | // add your custom rules here 21 | rules: { 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Node template 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | *.pid.lock 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # nyc test coverage 23 | .nyc_output 24 | 25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 26 | .grunt 27 | 28 | # Bower dependency directory (https://bower.io/) 29 | bower_components 30 | 31 | # node-waf configuration 32 | .lock-wscript 33 | 34 | # Compiled binary addons (https://nodejs.org/api/addons.html) 35 | build/Release 36 | 37 | # Dependency directories 38 | node_modules/ 39 | jspm_packages/ 40 | 41 | # TypeScript v1 declaration files 42 | typings/ 43 | 44 | # Optional npm cache directory 45 | .npm 46 | 47 | # Optional eslint cache 48 | .eslintcache 49 | 50 | # Optional REPL history 51 | .node_repl_history 52 | 53 | # Output of 'npm pack' 54 | *.tgz 55 | 56 | # Yarn Integrity file 57 | .yarn-integrity 58 | 59 | # dotenv environment variables file 60 | .env 61 | 62 | # parcel-bundler cache (https://parceljs.org/) 63 | .cache 64 | 65 | # next.js build output 66 | .next 67 | 68 | # nuxt.js build output 69 | .nuxt 70 | 71 | # Nuxt generate 72 | dist 73 | 74 | # Lambdas 75 | lambdas-dist 76 | 77 | # vuepress build output 78 | .vuepress/dist 79 | 80 | # Serverless directories 81 | .serverless 82 | 83 | # IDE 84 | .idea 85 | 86 | # Service worker 87 | sw.* 88 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true 4 | } 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Alexander Schwartzberg 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nuxt-netlify-lambda-starter 2 | 3 | :hammer_and_wrench: SEO-friendly website starter backed by Netlify lambda functions in a simple, friendly repo 4 | 5 | This is a basic starter project for a prerendered [Vue.js](https://vuejs.org/) + [Nuxt.js](https://nuxtjs.org/) frontend with a [Netlify lambda function](https://www.netlify.com/docs/functions/) backend. The Nuxt.js app is pre-rendered for improved SEO. 6 | 7 | ### [You can view the deployed app here](https://nuxt-netlify-lambda-starter.netlify.com/) 8 | 9 | ### Features 10 | - Home, About, and 404 Pages 11 | - `HelloWorld` example Lambda function with associated frontend code 12 | - Pre-rendered dynamic pages using a sample `Item` datatype 13 | - Integrates with [HotJar](https://hotjar.com"), [Mailchimp](https://mailchimp.com"), and [Google Analytics](https://analytics.google.com/analytics/web/#/) 14 | - Includes [JSON-LD Structured Data](https://developers.google.com/search/docs/guides/intro-structured-data) for outstanding SEO 15 | - Pre-configured with [OpenGraph](http://ogp.me/) and [Twitter Cards](https://developer.twitter.com/en/docs/tweets/optimize-with-cards/guides/getting-started.html) meta tags for beautiful [unfurls](https://medium.com/slack-developer-blog/everything-you-ever-wanted-to-know-about-unfurling-but-were-afraid-to-ask-or-how-to-make-your-e64b4bb9254) when sharing on social media 16 | - Customizable UI using [Bootstrap](https://getbootstrap.com) & [SASS](https://sass-lang.com) variables 17 | 18 | **NOTE:** this project can only be deployed via Netlify with [continuous deployment](https://www.netlify.com/docs/continuous-deployment/) enabled. 19 | 20 | ### Build Setup 21 | 22 | ``` bash 23 | # Install dependencies 24 | $ yarn install 25 | 26 | # Serve with hot reload at localhost:3000 and serves Netlify Functions 27 | $ yarn run dev 28 | 29 | # Build for production 30 | $ yarn run build 31 | ``` 32 | 33 | Note that [Prettier]() will automatically clean up your code when you save. You can adjust this behavior in the `build` section at line `127` in `nuxt.config.js`. 34 | 35 | ### Pre-rendered Dynamic Pages 36 | 37 | This project includes a series of pre-rendered pages using a generic `Item` datatype. The data for these pages is maintained in `assets/content/items.json` and they're generated with a custom `generate` field in `nuxt.config.js`: 38 | 39 | ```js 40 | generate: { 41 | routes: items.map(g => '/items/' + g.id) 42 | } 43 | ``` 44 | 45 | This ensures that each item has a page that's pre-renderd and SEO-optimized. You can clone, modify, or remove the `Item` datatype and associated pages to better suit your needs. 46 | 47 | ### Environment Configuration 48 | The following production environment variables are required for the respective plugins to work correctly: 49 | 50 | ```bash 51 | # Google Analytics Tracking Code 52 | GA_TRACKING_ID=UA-XXX-X 53 | 54 | # HotJar Site Identifier 55 | HOTJAR_SITE_ID=1234567 56 | 57 | # Mailchimp Script Variables 58 | MAILCHIMP_BASE_URL=mc.us19.list-manage.com 59 | MAILCHIMP_LID=abcde12345 60 | MAILCHIMP_UUID=aabbccddeeffgghhiijj12345 61 | ``` 62 | 63 | These variables can be configured in a variety of ways - please consult the [Netlify Continuous Deployment Docs](https://www.netlify.com/docs/continuous-deployment/#environment-variables). You can deactivate any of these plugins by modifying the `plugins` field in the `nuxt.config.js` file. 64 | 65 | ### JSON-LD Structured Data 66 | 67 | The [JSON-LD Structured Data](https://developers.google.com/search/docs/guides/intro-structured-data) can be updated by modifying the `jsonld()` function in the `layouts/default.vue` file. This feature shouldn't be used anywhere else - one `JSON-LD` snippet should describe the entire site. 68 | 69 | ### OpenGraph and Twitter Card Meta Tags 70 | 71 | The `` tags for [OpenGraph](http://ogp.me/) and [Twitter Cards](https://developer.twitter.com/en/docs/tweets/optimize-with-cards/guides/getting-started.html) are located in the `head` section of `nuxt.config.js`. **You should change these from their default values**. You can validate your changes using the [Twitter Card Validator](https://cards-dev.twitter.com/validator) and the [Facebook Sharing Debugger](https://developers.facebook.com/tools/debug/sharing). 72 | 73 | ### Bootstrap + SASS Configuration 74 | 75 | You can modify the `assets/sass/main.sass` file to optionally include Bootstrap component styles as-needed. **PROTIP** - only include the Bootstrap components your app depends on - this will keep your CSS bundle nice and slim :) 76 | 77 | You can also modify any of [Bootstrap's SASS Variables](https://github.com/twbs/bootstrap/blob/master/scss/_variables.scss) inside the `assets/sass/variables.sass` file to customize the framework to your liking. 78 | 79 | ### FontAwesome Vue Configuration 80 | 81 | The repo includes a minimal subset of icons by default. When you need an additional icon, you must import it directly in `plugins/fontawesome.js` and register it with the FontAwesome plugin. You can learn more about the Vue-FontAwesome library [here](https://github.com/FortAwesome/vue-fontawesome). 82 | 83 | ### References 84 | - [Vue.js](https://vuejs.org) 85 | - [Nuxt.js](https://nuxtjs.org) 86 | - [Netlify Functions](https://www.netlify.com/docs/functions/) 87 | - [Bootstrap-Vue](https://bootstrap-vue.js.org/) 88 | - [Bootstrap Components](https://getbootstrap.com/docs/4.3/components/alerts/) 89 | - [FontAwesome Vue](https://github.com/FortAwesome/vue-fontawesome) 90 | - [`netlify.toml` Docs](https://www.netlify.com/docs/netlify-toml-reference/) 91 | -------------------------------------------------------------------------------- /assets/README.md: -------------------------------------------------------------------------------- 1 | # ASSETS 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your un-compiled assets such as LESS, SASS, or JavaScript. 6 | 7 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#webpacked). 8 | -------------------------------------------------------------------------------- /assets/content/items.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "node", 4 | "label": "Node.js", 5 | "icon": "https://jaystack.com/wp-content/uploads/2015/12/nodejs-logo-e1497443346889.png", 6 | "description": "Node.js is useful!" 7 | }, 8 | { 9 | "id": "postman", 10 | "label": "Postman", 11 | "icon": "https://raw.githubusercontent.com/codotype/codotype-postman-collection-generator/master/postman.png", 12 | "description": "Postman is cool!" 13 | }, 14 | { 15 | "id": "vue", 16 | "label": "Vue.js", 17 | "icon": "https://res.cloudinary.com/codotype/image/upload/v1551192656/tech-logos/vue.png", 18 | "description": "Vue.js is fun!" 19 | }, 20 | { 21 | "id": "python", 22 | "label": "Python", 23 | "icon": "https://raw.githubusercontent.com/codotype/codotype-python-falcon-mongodb-generator/master/python.png", 24 | "description": "Python is simple, in a good way!" 25 | }, 26 | { 27 | "id": "react", 28 | "label": "React", 29 | "icon": "https://res.cloudinary.com/codotype/image/upload/v1553197668/tech-logos/react.png", 30 | "description": "React is versatile!" 31 | } 32 | ] 33 | -------------------------------------------------------------------------------- /assets/sass/main.sass: -------------------------------------------------------------------------------- 1 | 2 | // Bootstrap Variable Overrides (customize things here) 3 | @import './variables' 4 | 5 | // Bootstrap Required Core 6 | @import 'node_modules/bootstrap/scss/functions' 7 | @import 'node_modules/bootstrap/scss/variables' 8 | @import 'node_modules/bootstrap/scss/mixins' 9 | 10 | // Boostrap Optional Components 11 | // PROTIP - only include the Bootstrap modules you're actually using - this will keep your CSS bundle nice and slim :) 12 | @import 'node_modules/bootstrap/scss/reboot' 13 | @import 'node_modules/bootstrap/scss/type' 14 | @import 'node_modules/bootstrap/scss/images' 15 | @import 'node_modules/bootstrap/scss/code' 16 | @import 'node_modules/bootstrap/scss/grid' 17 | @import 'node_modules/bootstrap/scss/tables' 18 | @import 'node_modules/bootstrap/scss/forms' 19 | @import 'node_modules/bootstrap/scss/buttons' 20 | @import 'node_modules/bootstrap/scss/transitions' 21 | @import 'node_modules/bootstrap/scss/dropdown' 22 | @import 'node_modules/bootstrap/scss/button-group' 23 | @import 'node_modules/bootstrap/scss/input-group' 24 | @import 'node_modules/bootstrap/scss/custom-forms' 25 | @import 'node_modules/bootstrap/scss/nav' 26 | @import 'node_modules/bootstrap/scss/navbar' 27 | @import 'node_modules/bootstrap/scss/card' 28 | @import 'node_modules/bootstrap/scss/breadcrumb' 29 | @import 'node_modules/bootstrap/scss/pagination' 30 | @import 'node_modules/bootstrap/scss/badge' 31 | @import 'node_modules/bootstrap/scss/jumbotron' 32 | @import 'node_modules/bootstrap/scss/alert' 33 | @import 'node_modules/bootstrap/scss/progress' 34 | @import 'node_modules/bootstrap/scss/media' 35 | @import 'node_modules/bootstrap/scss/list-group' 36 | @import 'node_modules/bootstrap/scss/close' 37 | @import 'node_modules/bootstrap/scss/modal' 38 | @import 'node_modules/bootstrap/scss/tooltip' 39 | @import 'node_modules/bootstrap/scss/popover' 40 | @import 'node_modules/bootstrap/scss/carousel' 41 | @import 'node_modules/bootstrap/scss/utilities' 42 | @import 'node_modules/bootstrap/scss/print' 43 | -------------------------------------------------------------------------------- /assets/sass/variables.sass: -------------------------------------------------------------------------------- 1 | // This is where you can customize Bootstrap to look just the way your like 2 | // It includes all variables by default copied and pasted from Bootstrap's example 3 | // Doc: https://getbootstrap.com/docs/4.0/getting-started/theming/ 4 | 5 | // // // // 6 | 7 | $bg-color: #f5f6f9 !default // Example that makes your background color slightly off-white 8 | -------------------------------------------------------------------------------- /components/Item.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 35 | 36 | 40 | -------------------------------------------------------------------------------- /components/Navbar.vue: -------------------------------------------------------------------------------- 1 | 41 | 42 | 47 | 48 | 54 | -------------------------------------------------------------------------------- /components/README.md: -------------------------------------------------------------------------------- 1 | # COMPONENTS 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | The components directory contains your Vue.js Components. 6 | 7 | _Nuxt.js doesn't supercharge these components._ 8 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | moduleNameMapper: { 3 | '^@/(.*)$': '/$1', 4 | '^~/(.*)$': '/$1', 5 | '^vue$': 'vue/dist/vue.common.js' 6 | }, 7 | moduleFileExtensions: ['js', 'vue', 'json'], 8 | transform: { 9 | '^.+\\.js$': 'babel-jest', 10 | '.*\\.(vue)$': 'vue-jest' 11 | }, 12 | collectCoverage: true, 13 | collectCoverageFrom: [ 14 | '/components/**/*.vue', 15 | '/pages/**/*.vue' 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /lambdas/hello.js: -------------------------------------------------------------------------------- 1 | exports.handler = function(event, context, callback) { 2 | callback(null, { 3 | statusCode: 200, 4 | body: 'Hello, World' 5 | }) 6 | } 7 | -------------------------------------------------------------------------------- /layouts/README.md: -------------------------------------------------------------------------------- 1 | # LAYOUTS 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your Application Layouts. 6 | 7 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/views#layouts). 8 | -------------------------------------------------------------------------------- /layouts/default.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 42 | -------------------------------------------------------------------------------- /middleware/README.md: -------------------------------------------------------------------------------- 1 | # MIDDLEWARE 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your application middleware. 6 | Middleware let you define custom functions that can be run before rendering either a page or a group of pages. 7 | 8 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/routing#middleware). 9 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | # Doc: https://www.netlify.com/docs/netlify-toml-reference/ 2 | [build] 3 | command = "yarn build" 4 | functions = "lambdas-dist" 5 | publish = "dist" 6 | -------------------------------------------------------------------------------- /nuxt.config.js: -------------------------------------------------------------------------------- 1 | import pkg from './package' 2 | import items from './assets/content/items.json' 3 | 4 | export default { 5 | mode: 'universal', 6 | 7 | /* 8 | ** Headers of the page 9 | */ 10 | head: { 11 | title: pkg.name, 12 | meta: [ 13 | { charset: 'utf-8' }, 14 | { name: 'viewport', content: 'width=device-width, initial-scale=1' }, 15 | { hid: 'description', name: 'description', content: pkg.description }, 16 | 17 | // Twitter Card Meta 18 | // Doc: https://developer.twitter.com/en/docs/tweets/optimize-with-cards/guides/getting-started.html 19 | { property: 'twitter:card', content: 'summary' }, 20 | { property: 'twitter:site', value: '@aeksco' }, 21 | { property: 'twitter:creator', value: '@aeksco' }, 22 | 23 | // OpenGraph Meta 24 | // Doc: http://ogp.me/ 25 | { property: 'og:url', content: 'https://nuxt-netlify-lambda-starter.netlify.com' }, 26 | { property: 'og:type', content: 'website' }, 27 | { property: 'og:title', content: 'Nuxt Netlify Lambda Starter' }, 28 | { property: 'og:description', content: 'SEO-friendly website starter backed by Netlify lambda functions' }, 29 | { property: 'og:image', content: 'https://nuxtjs.org/meta_640.png' }, 30 | { property: 'og:image:height', content: 640 }, 31 | { property: 'og:image:width', content: 640 }, 32 | { property: 'og:image:type', content: 'image/png' }, 33 | { property: 'og:image:alt', content: 'Nuxt.js Logo' }, 34 | ], 35 | link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }] 36 | }, 37 | 38 | // Generate static pages for all Items 39 | // Must be done because Item routes are dynamic, 40 | // but all content is pulled from static data 41 | // Doc: https://nuxtjs.org/api/configuration-generate 42 | generate: { 43 | routes: items.map(g => '/items/' + g.id) 44 | }, 45 | 46 | router: { 47 | extendRoutes (routes, resolve) { 48 | routes.push({ 49 | name: 'custom', 50 | path: '*', 51 | component: resolve(__dirname, 'pages/404.vue') 52 | }) 53 | } 54 | }, 55 | 56 | /* 57 | ** Customize the progress-bar color 58 | */ 59 | loading: { color: '#fff' }, 60 | 61 | /* 62 | ** Global CSS 63 | */ 64 | css: [ 65 | '@/assets/sass/main.sass', 66 | '@fortawesome/fontawesome-svg-core/styles.css', 67 | ], 68 | 69 | /* 70 | ** Plugins to load before mounting the App 71 | */ 72 | plugins: [ 73 | '~/plugins/fontawesome.js', 74 | '~/plugins/jsonld.js', 75 | { src: '~plugins/ga.js', ssr: false }, 76 | { src: '~plugins/hotjar.js', ssr: false }, 77 | { src: '~plugins/mailchimp.js', ssr: false } 78 | ], 79 | 80 | /* 81 | ** Nuxt.js modules 82 | */ 83 | modules: [ 84 | '@nuxtjs/axios', 85 | '@nuxtjs/proxy', 86 | // Doc: https://bootstrap-vue.js.org/docs/ 87 | 'bootstrap-vue/nuxt', 88 | // Doc: https://www.npmjs.com/package/vue-github-buttons#using-with-nuxt 89 | 'vue-github-buttons/nuxt', 90 | ], 91 | 92 | // Bootstrap vue configuration 93 | bootstrapVue: { 94 | bootstrapCSS: false, // or `css` 95 | bootstrapVueCSS: false // or `bvCSS` 96 | }, 97 | 98 | // @nuxtjs/axios plugin configuration 99 | axios: { 100 | prefix: '/', 101 | baseUrl: '/', // For the server 102 | browserBaseURL: '/' 103 | }, 104 | 105 | // @nuxtjs/proxy configuration 106 | proxy: { 107 | '/.netlify': { 108 | target: 'http://localhost:9000', 109 | pathRewrite: { '^/.netlify/functions': '' } 110 | } 111 | }, 112 | 113 | // Frontend environment variables configuration 114 | // Doc: https://nuxtjs.org/api/configuration-env 115 | env: { 116 | HOTJAR_SITE_ID: process.env.HOTJAR_SITE_ID ? Number(process.env.HOTJAR_SITE_ID) : undefined, 117 | GA_TRACKING_ID: String(process.env.GA_TRACKING_ID), 118 | MAILCHIMP_BASE_URL: String(process.env.MAILCHIMP_BASE_URL), 119 | MAILCHIMP_UUID: String(process.env.MAILCHIMP_UUID), 120 | MAILCHIMP_LID: String(process.env.MAILCHIMP_LID) 121 | }, 122 | 123 | /* 124 | ** Build configuration 125 | */ 126 | build: { 127 | /* 128 | ** You can extend webpack config here 129 | */ 130 | extend(config, ctx) { 131 | // Run ESLint on save 132 | if (ctx.isDev && ctx.isClient) { 133 | config.module.rules.push({ 134 | enforce: 'pre', 135 | test: /\.(js|vue)$/, 136 | loader: 'eslint-loader', 137 | exclude: /(node_modules)/, 138 | options: { 139 | fix: true // NOTE - this is set to `true` so prettier automatically cleans up the file on save 140 | } 141 | }) 142 | } 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nuxt-netlify-lambda-starter", 3 | "version": "1.0.0", 4 | "description": "SEO-friendly website starter in Vue + Nuxt backed by Netlify lambda functions", 5 | "author": "Alexander Schwartzberg", 6 | "private": true, 7 | "scripts": { 8 | "dev:frontend": "nuxt", 9 | "dev:lambdas": "netlify-lambda serve lambdas", 10 | "dev": "run-p dev:*", 11 | "build:frontend": "nuxt generate", 12 | "build:lambdas": "netlify-lambda build lambdas", 13 | "build": "run-p build:*", 14 | "start": "nuxt start", 15 | "lint:js": "eslint --ext .js,.vue --ignore-path .gitignore .", 16 | "lint": "run-p lint:", 17 | "precommit": "npm run lint", 18 | "test": "jest" 19 | }, 20 | "dependencies": { 21 | "@fortawesome/fontawesome-svg-core": "^1.2.17", 22 | "@fortawesome/free-brands-svg-icons": "^5.8.1", 23 | "@fortawesome/free-solid-svg-icons": "^5.8.1", 24 | "@fortawesome/vue-fontawesome": "^0.1.6", 25 | "@nuxtjs/axios": "^5.3.6", 26 | "@nuxtjs/proxy": "^1.3.1", 27 | "dotenv": "^6.2.0", 28 | "bootstrap": "^4.3.1", 29 | "bootstrap-vue": "^2.0.0-rc.11", 30 | "cross-env": "^5.2.0", 31 | "nuxt": "^2.4.0", 32 | "nuxt-jsonld": "^0.0.6", 33 | "vue-github-buttons": "^3.1.0" 34 | }, 35 | "devDependencies": { 36 | "@nuxtjs/eslint-config": "^0.0.1", 37 | "@vue/test-utils": "^1.0.0-beta.27", 38 | "babel-core": "7.0.0-bridge.0", 39 | "babel-eslint": "^10.0.1", 40 | "babel-jest": "^24.1.0", 41 | "eslint": "^5.15.1", 42 | "eslint-config-prettier": "^4.1.0", 43 | "eslint-config-standard": ">=12.0.0", 44 | "eslint-loader": "^2.1.2", 45 | "eslint-plugin-import": ">=2.16.0", 46 | "eslint-plugin-jest": ">=22.3.0", 47 | "eslint-plugin-node": ">=8.0.1", 48 | "eslint-plugin-nuxt": ">=0.4.2", 49 | "eslint-plugin-prettier": "^3.0.1", 50 | "eslint-plugin-promise": ">=4.0.1", 51 | "eslint-plugin-standard": ">=4.0.0", 52 | "eslint-plugin-vue": "^5.2.2", 53 | "jest": "^24.1.0", 54 | "netlify-lambda": "^1.3.1", 55 | "node-sass": "^4.11.0", 56 | "nodemon": "^1.18.9", 57 | "npm-run-all": "4.1.x", 58 | "prettier": "^1.16.4", 59 | "sass-loader": "^7.1.0", 60 | "vue-cli-plugin-netlify-lambda": "^0.1.1", 61 | "vue-jest": "^3.0.3" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /pages/404.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 47 | -------------------------------------------------------------------------------- /pages/README.md: -------------------------------------------------------------------------------- 1 | # PAGES 2 | 3 | This directory contains your Application Views and Routes. 4 | The framework reads all the `*.vue` files inside this directory and creates the router of your application. 5 | 6 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/routing). 7 | -------------------------------------------------------------------------------- /pages/about.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 40 | -------------------------------------------------------------------------------- /pages/hello.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 48 | -------------------------------------------------------------------------------- /pages/index.vue: -------------------------------------------------------------------------------- 1 | 147 | 148 | 164 | 165 | 177 | -------------------------------------------------------------------------------- /pages/items/_id/index.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 35 | -------------------------------------------------------------------------------- /pages/items/index.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 49 | -------------------------------------------------------------------------------- /pages/lambdas/hello.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 73 | -------------------------------------------------------------------------------- /pages/lambdas/index.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 40 | -------------------------------------------------------------------------------- /plugins/README.md: -------------------------------------------------------------------------------- 1 | # PLUGINS 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains Javascript plugins that you want to run before mounting the root Vue.js application. 6 | 7 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/plugins). 8 | -------------------------------------------------------------------------------- /plugins/fontawesome.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import { library, config } from '@fortawesome/fontawesome-svg-core' 3 | import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' 4 | import { faTwitter, faGithub } from '@fortawesome/free-brands-svg-icons' 5 | import { 6 | faHeart, 7 | faQuestionCircle, 8 | faSpinner 9 | } from '@fortawesome/free-solid-svg-icons' 10 | 11 | // This is important, we are going to let Nuxt.js worry about the CSS 12 | config.autoAddCss = false 13 | 14 | // You can add your icons directly in this plugin. See other examples for how you 15 | // can add other styles or just individual icons. 16 | // Doc: https://github.com/FortAwesome/vue-fontawesome 17 | 18 | // FontAwesome Core Icons 19 | library.add(faHeart) 20 | library.add(faQuestionCircle) 21 | library.add(faSpinner) 22 | 23 | // FontAwesome Brand Icons 24 | library.add(faTwitter) 25 | library.add(faGithub) 26 | 27 | // Register the component globally 28 | Vue.component('font-awesome-icon', FontAwesomeIcon) 29 | -------------------------------------------------------------------------------- /plugins/ga.js: -------------------------------------------------------------------------------- 1 | // Doc: https://nuxtjs.org/faq/google-analytics/ 2 | 3 | /* eslint-disable */ 4 | 5 | export default ({ app }) => { 6 | // Only run on client-side and only in production mode 7 | if (process.env.NODE_ENV !== 'production') return; 8 | 9 | // Short-circuit this function if required env variable is undefined 10 | if (!process.env.GA_TRACKING_ID) return; 11 | 12 | // Include Google Analytics Script 13 | (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ 14 | (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), 15 | m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) 16 | })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); 17 | 18 | // Set the current page 19 | ga('create', process.env.GA_TRACKING_ID, 'auto') 20 | 21 | // Every time the route changes (fired on initialization too) 22 | app.router.afterEach((to, from) => { 23 | 24 | // We tell Google Analytics to add a `pageview` 25 | ga('set', 'page', to.fullPath) 26 | ga('send', 'pageview') 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /plugins/hotjar.js: -------------------------------------------------------------------------------- 1 | // Doc: https://nuxtjs.org/faq/google-analytics/ 2 | 3 | /* eslint-disable */ 4 | 5 | export default ({ app }) => { 6 | // Only run on client-side and only in production mode 7 | if (process.env.NODE_ENV !== 'production') return 8 | 9 | // Short-circuit this function if required env variable is undefined 10 | if (!process.env.HOTJAR_SITE_ID) return 11 | 12 | // Hotjar Tracking Code defined under process.env.HOTJAR_SITE_ID 13 | (function(h,o,t,j,a,r){ 14 | h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)}; 15 | h._hjSettings={hjid:process.env.HOTJAR_SITE_ID,hjsv:6}; 16 | a=o.getElementsByTagName('head')[0]; 17 | r=o.createElement('script');r.async=1; 18 | r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv; 19 | a.appendChild(r); 20 | })(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv='); 21 | 22 | } 23 | 24 | -------------------------------------------------------------------------------- /plugins/jsonld.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import NuxtJsonld from 'nuxt-jsonld' 3 | 4 | Vue.use(NuxtJsonld) 5 | -------------------------------------------------------------------------------- /plugins/mailchimp.js: -------------------------------------------------------------------------------- 1 | // Doc: https://nuxtjs.org/faq/google-analytics/ 2 | 3 | /* eslint-disable */ 4 | 5 | export default ({ app }) => { 6 | // Only run on client-side and only in production mode 7 | if (process.env.NODE_ENV !== 'production') return; 8 | 9 | // Short circuit if the required env variables aren't available 10 | if (!process.env.MAILCHIMP_BASE_URL || !process.env.MAILCHIMP_UUID || !process.env.MAILCHIMP_LID) return; 11 | 12 | /* eslint-disable */ 13 | 14 | // Add Mailchimp popup loader script 15 | const chimpPopupLoader = document.createElement("script"); 16 | chimpPopupLoader.type = 'text/javascript' 17 | chimpPopupLoader.src = '//downloads.mailchimp.com/js/signup-forms/popup/unique-methods/embed.js'; 18 | chimpPopupLoader.setAttribute('data-dojo-config', 'usePlainJson: true, isDebug: false'); 19 | 20 | // // Load Mailchimp signup form script 21 | const chimpPopup = document.createElement("script"); 22 | chimpPopup.type = 'text/javascript' 23 | chimpPopup.appendChild(document.createTextNode('window.dojoRequire(["mojo/signup-forms/Loader"], function(L) { L.start({"baseUrl": "' + process.env.MAILCHIMP_BASE_URL + '", "uuid": "' + process.env.MAILCHIMP_UUID + '", "lid": "' + process.env.MAILCHIMP_LID + '", "uniqueMethods":true})});')); 24 | 25 | // Add the Mailchimp loader when the page loads 26 | chimpPopupLoader.onload = function() { 27 | document.body.appendChild(chimpPopup); 28 | } 29 | 30 | // Add the Mailchimp popup loader to the body 31 | document.body.appendChild(chimpPopupLoader); 32 | } 33 | -------------------------------------------------------------------------------- /static/README.md: -------------------------------------------------------------------------------- 1 | # STATIC 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your static files. 6 | Each file inside this directory is mapped to `/`. 7 | Thus you'd want to delete this README.md before deploying to production. 8 | 9 | Example: `/static/robots.txt` is mapped as `/robots.txt`. 10 | 11 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#static). 12 | -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aeksco/nuxt-netlify-lambda-starter/83cb58059e38132e6793f7cac3d3a1f65105dd36/static/favicon.ico -------------------------------------------------------------------------------- /static/robots.txt: -------------------------------------------------------------------------------- 1 | User-Agent: * 2 | Disallow: 3 | Allow: /about 4 | Allow: /mylambda 5 | -------------------------------------------------------------------------------- /store/README.md: -------------------------------------------------------------------------------- 1 | # STORE 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your Vuex Store files. 6 | Vuex Store option is implemented in the Nuxt.js framework. 7 | 8 | Creating a file in this directory automatically activates the option in the framework. 9 | 10 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/vuex-store). 11 | -------------------------------------------------------------------------------- /test/Logo.spec.js: -------------------------------------------------------------------------------- 1 | import { mount } from '@vue/test-utils' 2 | import Logo from '@/components/Logo.vue' 3 | 4 | describe('Logo', () => { 5 | test('is a Vue instance', () => { 6 | const wrapper = mount(Logo) 7 | expect(wrapper.isVueInstance()).toBeTruthy() 8 | }) 9 | }) 10 | --------------------------------------------------------------------------------