- Run
yarn create nuxt-app my-project
with the following options:- Project name: (leave default)
- Programming language: JavaScript
- Package manager: Yarn
- UI framework: Buefy
- Nuxt.js modules: Progressive Web App (PWA)
- Linting tools: ESLint
- Testing framework: None
- Rendering mode: Universal (SSR / SSG)
- Deployment target: Server (Node.js hosting)
- Development tools: jsconfig.json (Recommended for VS Code if you're not using typescript)
- Continuous integration: None
- Version control system: Git
-
Delete files
rm assets/README.md rm components/README.md rm layouts/README.md rm middleware/README.md rm pages/README.md rm plugins/README.md rm static/README.md rm store/README.md rm components/Card.vue rm components/Logo.vue rm pages/inspire.vue rm assets/buefy.png
-
Replace nuxt filler content with base content:
<!-- layouts/default.vue --> <template> <div> <div class="container"> <nuxt /> </div> </div> </template>
<!-- pages/index.vue --> <template> <section class="section"> <h1> Home </h1> </section> </template>
-
Create similar placeholder pages:
pages/about.vue pages/private.vue
-
Create projects in Firebase console (create a prod project and a test project)
-
For each project, upgrade to Blaze Plan and assign to billing account (create new billing account if needed)
-
In the Firebase console, set up Firestore - choose production mode (deny all requests by default) and region
-
Run
firebase init
in root project directory- Choose features: Firestore, Functions, Hosting, Storage, Emulators
- Choose project (or create new)
- Use default
firestore.rules
- Use default
firestore.indexes.json
- Choose language: Javascript
- Use ESLint: Yes
- Do not install dependencies now
- Public directory:
public
- Single Page App: No
- Automatic builds and deploys: No
- Use default
storage.rules
- Select emulators: Authentication, Functions, Firestore, Hosting
- Use default ports for emulators
- Enable the Emulator UI: Yes
- Emulator UI Port:
4000
- Download emulators now: No
-
Add the following to
.gitignore
:# Firebase /.firebase .firebaserc
-
Update
.firebaserc
- Run
cp .firebaserc example.firebaserc
- Update
example.firebaserc
with sample project IDs fordefault
(test) andprod
- Update
.firebaserc
with actual project IDs fordefault
(test) andprod
- Run
-
Move Nuxt directories into
/src
(assets
,components
,layouts
,middleware
,pages
,plugins
,static
,store
) -
Add the following to
.gitignore
:# SSR /public
-
Add the following to
functions/.gitignore
:# functions/package.json is generated at build time /package.json
-
Use
yarn
instead ofnpm
infirebase.json
:"functions": { "predeploy": [ "yarn --prefix \"$RESOURCE_DIR\" lint" ] }
-
In
firebase.json
, add:"hosting": { "rewrites": [ { "source": "**", "function": "nuxtssr" } ] }
-
Set the following in
nuxt.config.js
:build: { // Static URLs should be generated with '/assets/' at the beginning of the path instead of '/_nuxt/', // so that they will be loaded from the CDN via Firebase Hosting, and not processed through the SSR cloud function publicPath: '/assets/' }, // Nuxt directories are in /src instead of in the root directory srcDir: 'src', // Compiled app needs to be in /functions so that Cloud Functions has access to it (to do the server-side rendering) buildDir: 'functions/.nuxt'
-
Add the following scripts to
package.json
:"postinstall": "node ./functions_install.js", "precommit": "yarn lint", "prebuild": "yarn clean && yarn lint", "postbuild": "yarn copyassets && yarn copystatic", "clean": "yarn clean:public && yarn clean:functions", "clean:public": "mkdir -p ./public && rimraf ./public/*", "clean:functions": "mkdir -p ./functions/.nuxt && rimraf ./functions/.nuxt/*", "copyassets": "mkdir -p ./public/assets && cp -R ./functions/.nuxt/dist/client/* ./public/assets", "copystatic": "cp -R ./src/static/* ./public", "serve": "DEBUG=nuxt:* firebase serve --only hosting,functions -p 3000", "build:serve": "yarn build && yarn serve", "deploy": "firebase deploy -P default", "buildDeploy": "yarn build && yarn deploy", "buildDeploy:prod": "DEPLOY_ENV=prod yarn build && firebase deploy -P prod"
-
Add the following sections to
package.json
. Install these packages withyarn
normally first, then move the lines to this section (the versions listed here are not real)."firebaseFunctionsDependencies": { "firebase-admin": "~0.0.0", "firebase-functions": "^0.0.0" }, "firebaseFunctionsExcludeDependencies": [ ]
-
Set the node version in
package.json
:"engines": { "node": "12" }
-
Set the node version in
firebase.json
:"functions": { "runtime": "nodejs12" },
-
Add the following files in the root directory:
functions_install.js generate_functions_package_json.js
-
Add the
nuxtssr
function:functions/nuxtssr.js
-
Export the
nuxtssr
function infunctions/index.js
(remove all of the default content):exports.nuxtssr = require('./nuxtssr').default
-
Create the following files:
# Development/Test environment .env # Production environment prod.env # Insert same variables here with example values example.env
-
Add app configuration values to
.env
files:APP_TITLE=My Project APP_DESCRIPTION=My Project Description APP_DOMAIN=my-project.example.com
-
Add the following to
.gitignore
:# Environment configuration prod.env
-
Install dotenv:
yarn add -D dotenv
-
Insert the following at the top of
nuxt.config.js
:const dev = process.env.DEPLOY_ENV !== 'prod' require('dotenv').config({ path: dev ? '.env' : 'prod.env' })
-
Update the
head
configuration innuxt.config.js
to reference theAPP_TITLE
andAPP_DESCRIPTION
environment variables:head: { title: process.env.APP_TITLE, meta: [ { hid: 'description', name: 'description', content: process.env.APP_DESCRIPTION } ] }
-
Update
nuxt.config.js
to inject necessary environment variables into the client app.Do not inject secret environment variables that are not intended for use in a client app.
env: { APP_TITLE: process.env.APP_TITLE, APP_DESCRIPTION: process.env.APP_DESCRIPTION, APP_DOMAIN: process.env.APP_DOMAIN }
-
Install node-sass and sass-loader. At the time of this writing, Bulma is only compatible with
node-sass@^4.0.0
.yarn add -D node-sass@^4.0.0 sass-loader
-
Install @nuxtjs/style-resources so that sass variables will be exposed to Vue components:
yarn add -D @nuxtjs/style-resources
-
Add the following files to
src/assets/scss/
:# Override bulma/buefy variables that do not depend on bulma variables # Import Bulma utilities (includes variables) # Override bulma/buefy variables that depend on bulma variables # Import mixins.scss variables.scss # Define mixins needed in components mixins.scss # Import variables.scss # Import bulma and buefy source files needed for this app buefy-custom.scss # Import buefy-custom.scss # Define additional global styles main.scss
-
Set the following in
nuxt.config.js
to load sass resources:css: [ // Main scss code to compile '~assets/scss/main.scss' ], styleResources: { scss: [ // Expose sass variables in Vue components '~assets/scss/variables.scss' ] }, modules: [ // Set css to false to not include default buefy CSS (we will compile our own) ['nuxt-buefy', { css: false }], // Expose variables to components automatically. See styleResources configuration above '@nuxtjs/style-resources' ], build: { // Extract CSS to dedicated CSS files in production extractCSS: !dev }
-
Install packages:
yarn add firebase @nuxtjs/firebase
-
Add example Firebase configuration values to
example.env
:# Firebase configuration # Get it from https://console.firebase.google.com # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FIREBASE_CONFIG_API_KEY=SoMeLeTtErS-MOreLetTErSAnDNumb3r5 FIREBASE_CONFIG_AUTH_DOMAIN=auth-domain.example.com FIREBASE_CONFIG_DATABASE_URL=https://my-project.firebaseio.com FIREBASE_CONFIG_PROJECT_ID=my-project FIREBASE_CONFIG_STORAGE_BUCKET=my-project.appspot.com FIREBASE_CONFIG_MESSAGING_SENDER_ID=012345678901 FIREBASE_APP_ID=1:123456789012:web:abc123abc123abc123abc1
-
Add real Firebase configuration values in
.env
andprod.env
-
Add
@nuxtjs/firebase
configuration tonuxt.config.js
:[ '@nuxtjs/firebase', { config: { apiKey: process.env.FIREBASE_CONFIG_API_KEY || '', authDomain: process.env.FIREBASE_CONFIG_AUTH_DOMAIN || '', databaseURL: process.env.FIREBASE_CONFIG_DATABASE_URL || '', projectId: process.env.FIREBASE_CONFIG_PROJECT_ID || '', storageBucket: process.env.FIREBASE_CONFIG_STORAGE_BUCKET || '', messagingSenderId: process.env.FIREBASE_CONFIG_MESSAGING_SENDER_ID || '', appId: process.env.FIREBASE_APP_ID || '', measurementId: process.env.FIREBASE_MEASUREMENT_ID || '' }, services: { auth: { initialize: { onAuthStateChangedAction: 'auth/loadUser' } }, firestore: true, functions: true, storage: true }, onFirebaseHosting: true } ]
-
Add
nuxt-vuex-router-sync
for handling#sign-in
URL hash:yarn add nuxt-vuex-router-sync
// nuxt.config.js modules: [ 'nuxt-vuex-router-sync', ]
-
Add
Object.pick
function insrc/plugins/helpers.js
. Register the plugin:// nuxt.config.js plugins: [ { src: '~/plugins/helpers.js' } ]
-
Add auth store in
src/store/auth.js
-
Add stores:
src/store/index.js src/store/pages.js
Client-side DOM must match SSR DOM until after hydration is complete. Otherwise, Nuxt will perform a full client-side render, removing one benefit of SSR. Elements that are only rendered on the client, or elements rendered differently on the client, should wait until hydrated === true
before rendering.
-
Add
hydrated
to thestate
in the root store, with thesetHydrated
mutation. -
Map
hydrated
andsetHydrated
to the default layout usingmapState
andmapMutations
. Execute thesetHydrated
mutation to sethydrated = true
in themounted
hook.
-
Add file
src/middleware/general.js
. -
Register middleware in
src/layouts/default.vue
:<script> export default { middleware: [ 'general' ] } </script>
- Add
head()
function and associated vuex state (usingmapState
andmapGetters
) tosrc/layouts/default.vue
.
-
Add files:
src/static/logo.svg src/static/logo-animated.svg src/static/logo-title.png src/static/social-image.png src/static/favicon.ico
-
Install packages
yarn add nuxt-fontawesome yarn add @fortawesome/free-brands-svg-icons yarn add @fortawesome/free-solid-svg-icons
-
Update
nuxt.config.js
to integrate with Buefy's icon component and specify which icons are needed:modules: [ ['nuxt-buefy', { materialDesignIcons: false, defaultIconPack: 'fas', defaultIconComponent: 'font-awesome-icon' } ], ['nuxt-fontawesome', { imports: [ { set: '@fortawesome/free-brands-svg-icons', icons: ['faGoogle', 'faFacebookF'] }, { set: '@fortawesome/free-solid-svg-icons', icons: ['faBars', 'faUser', 'faCog', 'faSignOutAlt'] } ] } ] ]
-
Icons can then be used in components with:
<b-icon icon="bars" /> <!-- uses default pack "fas" --> <b-icon pack="fab" icon="google" />
-
Add container/page layout helpers:
src/components/Container.vue src/components/PageContainer.vue
-
Update pages to use the
PageContainer
component. For example,src/pages/index.vue
:<template> <PageContainer title="Welcome!"> <p>Homepage</p> </PageContainer> </template> <script> import PageContainer from '~/components/PageContainer.vue' export default { components: { PageContainer } } </script>
-
Add structural component files:
src/components/Footer.vue src/components/Loading.vue src/components/Login.vue src/components/Navbar.vue src/mixins/clickoff.js
-
Update
src/layouts/default.vue
(see complete file for code):- Update the template to use the structural components
- Add auth-related mapped state and getters to the
computed
object - Add the
style
tag
-
Include needed
bulma
andbuefy
elements and components insrc/assets/scss/buefy-custom.scss
@import '~bulma/sass/elements/button.sass'; @import '~bulma/sass/elements/container.sass'; @import '~bulma/sass/elements/content.sass'; @import '~bulma/sass/elements/icon.sass'; @import '~bulma/sass/elements/notification.sass'; @import '~bulma/sass/elements/progress.sass'; @import '~buefy/src/scss/components/_icon.scss'; @import '~buefy/src/scss/components/_loading.scss';
-
Update
src/assets/main.scss
to set main DOM elements to full height. This allows the footer to be at the bottom of the viewport when the page would otherwise be too short to fill the viewport.html, body, #__nuxt, #__layout { height: 100%; }
-
Set color variables in
src/assets/scss
# Install dependencies
yarn install
# Test locally
yarn build:serve
# Deploy to test project
yarn buildDeploy