Install command line: sudo npm install -g nuxt
Using starter template - this is most project should start
Start from scratch - nice to have, demonstrate how it could be
Also do this: (see https://github.com/facebook/create-react-app/issues/4227)
echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
Read https://www.academind.com/learn/vue-js/nuxt-js-tutorial-introduction/static-site-generation/
Server side rendering: default enabled, pre-render on the fly pages on the server, improved SEO, but needs to run a node.js server
Issues: "Mismatching childNodes vs. VNodes" - sometimes server and client DOM does not match. This could be caused by some plugin should not run on server side (disable with 'ssr' option), or some other mysterious reasons. It seems that then fallback works, and so this is only a warning (only on dev mode). To get rid of this warning, either disable the plugin on serve side, find and correct the problematic HTML tag, or disable server rendering of a DOM node with <no-ssr>...</no-ssr>, or simply disable SSR at all.
SPA: can host on a static website host, but lose pre-rendering and the improved SEO; use "nuxt --spa" to run in SPA mode.
Nuxt generate: seems very powerful, read the above article.
See https://github.com/nuxt/nuxt.js/issues/2341
With VS Code:
{
"name": "Debug Hare Dev",
"type": "node",
"request": "launch",
"protocol": "inspector",
"program": "${workspaceRoot}/node_modules/.bin/nuxt",
"stopOnEntry": false,
"args": ["dev"],
"cwd": "${workspaceRoot}",
"sourceMaps": true,
"env": {
"NODE_ENV": "development",
"DEBUG": "nuxt:*,app"
}
},
{
"type": "chrome",
"request": "launch",
"name": "Launch Chrome localhost 3000",
"sourceMapPathOverrides": {
"webpack:/*": "${webRoot}/*"
},
"url": "http://localhost:3000",
"webRoot": "${workspaceFolder}"
},
Gotchas:
Understand if the code is running on server (modules), on browser, or both (ssr)
In nuxt.config.js it seems the following code is needed to make break point show at the right place
build: {
/*
** Run ESLint on save
*/
extend (config, { isDev, isClient }) {
// https://cmty.app/nuxt/nuxt.js/issues/c2413#comment-5b35a3a91f90bd927cce61ac
if (isDev || isClient) {
config.devtool = '#source-map' // Something you like
}
If the loaded .vue or js is ES6 - means if uses "import {Something} from 'something'" but not "const Something = require('something')" - then at least the imported module local variable cannot be find. The variable is there, but of a different name, __WEBPACK... something. To solve this, change import to require, or just try to find that different name from "Local" in "Sources" tab in chrome inspector.
Also it seems something optimized the code in a way that, in a .vue template, in a method, if a outer variable (like imported module) is not used, then at the breakpoint it cannot be accessed. However if I console.log(thatVariable), thatVariable is available then!
Choose a most suitable devtool. Choose "eval" to see the "real code". See devtool doc here.
module.exports = {
build: {
extend (config, { isDev, isClient }) {
if (isDev && isClient) {
config.devtool = '#source-map'
}
}
}
When use Google Chrome inspector, find the code at source tab "webpack-internal://" and note the source ONLY APPEAR AFTER loaded (accessed the page etc.)
Aliases: "~" or "@", such as "~/assets/", indicate srcDir which is by default same as rootDir; "~~" or "@@" roodDir
assets - un-compiled assets such as style sheets and javascript, webpacked, when referred such as "~/assets/..." will be translated into "require".. and be loaded by loaders (css loader, file loader, url loader, etc.)
static - assets not loaded by loader, not webpacked, accessible from root URL
components - Vue components, not supercharged (without Nuxt added)
layouts - see below
middleware - custom functions to be run before rendering one or a group of pages (layouts)
pages - views and routers, scanned by framework to create router
plugins -
store - vuex store, create an index.js inside the directory enables the option
nuxt.config.js - configuration
build :
plugins - array of plugins to load
vendor - add external modules to reduce size of bundle, can be npm module or a path from '~/"
modules - list of modules
many other configurations available, see document
Routing is generated from "pages" directory. Navigation better to use <nuxt-link> component.
Supports (IMPORTANT consider if hosting in static service such as S3):
Basic routes - page dir structure maps to url, each page of its own
Dynamic routes
/users/_id.vue (path parameter not necessarily appear in the end, can be anywhere), route /users/:id? makes id optional
/users/_id/index.vue, route /users/:id, required
inside the vue component, can provide validate({ params }){...return true;} to validate parameter
IMPORTANT: if use static hosting, may enable in nuxt.config.js:
generate: {
fallback: 'error.html', // for default AWS S3 static hosting
}
Nested routes
provide both /users/child.vue and /users.vue, users.vue would be parent component, inside it must write <nuxt-child/>
child components: index.vue be the default, also allow parameter component such as _id.vue
Dynamic nested routes - possible
Single page application fallback - if enabled, output extra file that is same as index.html in spa mode, then in static hosting servers configure to use it if no file matches to fall back to SPA
Serge (simple CDN) supported
Page transition (animation effect) supported
Alternatively, there's a module to specify router instead of generate from pages
export default function (context) {
...
}
Can be configured to be called for each router change, etc.
Document (HTML file) ->
Layout (Vue component + optional middleware & head) ->
Page (Vue component supercharged with Nuxt options) - asyncData, fetch, head, layout, middleware, scrollToTop, transition, validate ->
Page child (supercharged) / Vue component (+nuxt head option)
app.html at root dir similar to the default template
In "layouts" dir, vue components, custom layout or error page.
Error page: layouts/error.vue, no <nuxt/>, see sample
Custom layout must include <nuxt/> component, referred to by pages to use.
Vue component with Nuxt supercharges:
asyncData - works for serverside rendering, also work in generated static site, called every time (but not the first time in generated static site) before page loading, result will be merged with component's data. See https://github.com/nuxt/nuxt.js/issues/1500
fetch - fill the store before rendering (called with context which includes store and path params, fetch some data then store commit), like data method but doesn't set component data but supposed to commit store. also works in server-side-rendering and generate static (in generated static site, page first load will not fetch but use the fetched content in build, when user click away then back fetch will be called again, see https://github.com/nuxt/nuxt.js/issues/1500)
head - set mega tags for current page
layout - specify a layout
loading - if false, prevent calling loading start() finish() to manually control the behavior
transition - page transition
scrollToTop - if true, scroll to top before rendering
validate - for dynamic routes
middleware
Details:
asyncData - Server side data fetching and rendering without using store (works in generated static site). Called every time before loading pages. Provide a method (context, callback){}, fetch some data and Nuxt will merge it with component data. (has NO access to component because it's called before component initialization).
Return
Return the data { 'dataKey':'dataValue'}
Return a Promise that resolve to data
Use async/await
Define a callback as second argument and callback(err, data)
Context:
context.params: access route data such as route parameter
context.error: return status and render error page from server side
When called / not called:
Called when navigate to page
Not called when query string change by default. To change, setup watchQuery (server only)
fetch: like asyncData method but does not set component data
Note: from 2.0 vendors will be gone and the work will be done automatically. See https://medium.com/nuxt/nuxt-2-is-coming-oh-yeah-212c1a9e1a67
Without vendors, external libraries work, but when imported in multiple pages, the page bundle will bloat.
To properly use external libraries, in nuxt.config.js add the library, then import as usual.
module.exports = {
build: {
vendor: ['axios']
}
}
How it works: Put a javascript file in "plugins" dir, and the path in nuxt.config.js. Then the javascript file will be imported before initialization of main client application. Appropriate to use "Vue.use()". NOTE: if the plugin uses an external library, should also include in "vendor"
Configuration:
module.exports = {
plugins: ['~/plugins/vue-notifications']
}
Configuration item in the array: string, or object {src: string, ssr:boolean} to turn off server side include.
Inject in $root and context:
In plugin javascript, can "export default" a function (context,inject) =>{}, and app will be available in the context. context appears to be the Nuxt context https://nuxtjs.org/api/context. Document not complete at the moment, need to check vue-i18n example. Not sure when that function get called.
Able to know if inside a generated app (nuxt generate), check process.static, or if bring server rendered during nuxt generate, check process.static && process.server.
Without module, Nuex can still be extended, but tedious, repetitious. Modules:
Can customize almost ANY aspects (plugins etc.).
Are just functions that are called sequentially when booting up on server, or build.
Can be incorporated into npm packages, made easy to reuse.
Module Javascript:
module.exports = function SimpleModule (moduleOptions) {
// Write your code here
}
// REQUIRED if publishing as an npm package
// module.exports.meta = require('./package.json')
Inside the function:
moduleOptions - options passed in using modules array
this - ModuleContainer, use it to customize Nuxt in anyway (add vendor, template, plugin, etc.)
this.options - the nuxt options: this is nuxt.config.js with all default options assigned to, can be used for sharing options between modules
this.nuxt - the current Nuxt instance. All modules have access to it. Can register hooks on life cycle events.
module.exports.meta - required if publishing module as npm package.
Use module:
module.exports = {
modules: [
// Simple usage
'~/modules/simple'
// Passing options
['~/modules/simple', { token: '123' }]
]
}
Asynchronous modules supported, see document.
One big difference between module and plugin: module is run when nuxt boot up, on server or upon build. Module can add plugin, but cannot run plugin. Plugin should be run on client.
To start development of a module as a npm package, start with the module template: https://github.com/nuxt-community/module-template.
In the module template, "this.addPlugin({src:..., fileName:..., options}):
src is the plugin file
fileName is the plugin file added to the application - this file is the src after processed with lodash template
options is the object passed to the lodash template engine
Template plugins: registered template and plugins can leverage lodash template. Use lodash template in plugins and template can "conditional compile", or code generate, the finally added template.
One usage of the template plugin is to pass JSON objects to the plugin.
In plugin:
const options = <%= JSON.stringify(options) %>
In module:
this.addPlugin({
src: resolve(__dirname, 'aws-amplify-plugin.js'),
fileName: 'nuxt-amplify.js',
options
})
Ready to use modules:
https://github.com/nuxt-community
To activate: just add "index.js" in "store" directory. May need to run "npm install" again but then should be all set. "this.$store" becomes available in pages and components.
BUG: in nuxt store don't give initial value "undefined" for the bug I reported here https://github.com/nuxt/nuxt.js/issues/3825
nuxtServerInit action hook: called with the context for every page only at sever, only works on the primary module in Modules mode, can be async function which must return a Promise
There's a module 'nuxt-i18n' that seems function rich and works fine, but then I encountered this issue: https://github.com/kazupon/vue-i18n/issues/184
Using $t in a promise cause problem.
Someone provides a work around this.$root.$t instead of this.$t, it works.
Someone pointed to this example:
https://nuxtjs.org/examples/i18n
Haven't tried due to not enough time. This example does not use nuxt-i18n.
<template>
<div v-html="content">
<nuxt-link :to="localePath('index')">link</nuxt-link>
{{$t("messageKey")}}
<p v-html="htmlContent"></p>
</div>
</template>
<script>
import axios from "axios";
export default {
data: () => ({
htmlContent: "<h1>Oh hi!</h1>",
}), // data
methods: {
// method1: function(event){},
},
computed: {
// computed1: function(){return },
},
components: {
// component1: component1,
},
// fetch data & merge into data
// called on server ssr / client / generate
// ctx: https://nuxtjs.org/api/context/
// return {key:value}
asyncData(ctx) {
}
};
</script>
<style scoped>
</style>