關於我
Hunter
前端工程師
用 Nuxt.js 2.x 自幹一個部落格
大綱
1. 部落格功能介紹
2. 套件選用與指令介紹
3. Nuxt.js 2.x 簡介, 目錄結構, 設定檔, 生命週期
4. Vuetify 1.3.x 簡介與 vuetify-loader 導入
5. Storybook 4 簡介與導入
6. 部落格: 佈局介紹 (/layouts)
7. 部落格: 所有元件介紹 (/components)
8. Firebase 簡介, 登入, 中間件, 資料庫
9. Vuex store & module registration
10. 部落格: 各頁面介紹 (/pages)
11. 部署 heroku, github pages, firebase hosting
12. 總結
1. 部落格功能介紹
2. 套件選用與指令介紹
3. Nuxt.js 2.x 簡介, 目錄結構, 設定檔, 生命週期
4. Vuetify 1.3.x 簡介與 vuetify-loader 導入
5. Storybook 4 簡介與導入
6. 部落格: 佈局介紹 (/layouts)
7. 部落格: 所有元件介紹 (/components)
8. Firebase 簡介, 登入, 中間件, 資料庫
9. Vuex store & module registration
10. 部落格: 各頁面介紹 (/pages)
11. 部署 heroku, github pages, firebase hosting
12. 總結
使用者模式
- 首頁
- 自我介紹
- 文章列表
- 標籤列表
- 文章內容
部落格功能介紹
開發者模式
- 登入
- 文章列表
- 發佈文章
- 編輯文章
使用者模式-首頁
使用者模式-自我介紹
使用者模式-文章列表
使用者模式-標籤列表
使用者模式-文章內容
開發者模式-登入
開發者模式-文章列表
開發者模式-發佈文章
開發者模式-編輯文章
寫篇文章吧!
1. 部落格功能介紹
2. 套件選用與指令介紹
3. Nuxt.js 2.x 簡介, 目錄結構, 設定檔, 生命週期
4. Vuetify 1.3.x 簡介與 vuetify-loader 導入
5. Storybook 4 簡介與導入
6. 部落格: 佈局介紹 (/layouts)
7. 部落格: 所有元件介紹 (/components)
8. Firebase 簡介, 登入, 中間件, 資料庫
9. Vuex store & module registration
10. 部落格: 各頁面介紹 (/pages)
11. 部署 heroku, github pages, firebase hosting
12. 總結
套件選用
- Lodash
- Disqus
- simple-vue-validator
- Codemirror
- markdown-it
- hightlight.js
套件選用與指令介紹
指令介紹
- dev
- storybook
- build
- analyze
- start
- plop
- generate
- generate:github
- generate:storybook
Lodash
1. uniq
2. flatten
3. camelCase
4. debounce
Lodash 是一個提供模組化、擁有優秀效能的函式庫。
(~24kB gzipped)
Lodash
只用了四個函式就要引入整個函式庫?
Lodash: tree-shaking
1. babel-plugin-lodash
2. lodash-webpack-plugin
Disqus
simple-vue-validator
simple-vue-validator 是一個表單驗證的解決方案
Why simple-vue-validator?
可以去參考我的鐵人賽
simple-vue-validator
1. 輕量 (~3.56kb gzipped)
2. 驗證邏輯和提交寫在 js
3. 錯誤訊息可以 js 組成,不污染 HTML
4. 唯一的遺憾,多國語系
5. 高彈性和可擴充性
simple-vue-validator
Codemirror
文字編輯器:codemirror
CodeMirror 是一個基於 javascript 的多功能的文字編輯器,可在瀏覽器中執行。
CodeMirror 提供程式碼的高亮和縮排等功能。
透過 vue-codemirror 實現
markdown-it
markdown-it 是一個 markdown 編譯器,
將 markdown 編譯為 html
highlight.js
Syntax highlighting for the Web
指令介紹
"scripts": {
"dev": "cross-env NODE_ENV=development nodemon server/index.js --watch server",
"storybook": "start-storybook -p 9002 -c .storybook",
"build": "nuxt build",
"analyze": "nuxt build -a",
"start": "nuxt start",
"plop": "plop --plopfile ./plop/index.js",
"generate": "nuxt generate",
"generate:github": "cross-env DEPLOY_ENV=GH_PAGES nuxt generate",
"generate:storybook": "build-storybook -c .storybook -o blog-storybook"
}
1. 部落格功能介紹
2. 套件選用與指令介紹
3. Nuxt.js 2.x 簡介, 目錄結構, 設定檔, 生命週期
4. Vuetify 1.3.x 簡介與 vuetify-loader 導入
5. Storybook 4 簡介與導入
6. 部落格: 佈局介紹 (/layouts)
7. 部落格: 所有元件介紹 (/components)
8. Firebase 簡介, 登入, 中間件, 資料庫
9. Vuex store & module registration
10. 部落格: 各頁面介紹 (/pages)
11. 部署 heroku, github pages, firebase hosting
12. 總結
Are you Nuxt?
Nuxt.js 簡介
Nuxt.js 是一個基於 Vue.js 的應用框架
Nuxt.js 依賴
1. Vue 2
2. Vue Router
3. Vuex
4. Vue Server Renderer (universal mode only)
5. vue-meta
Nuxt.js 提供三種模式
1. universal: 簡單理解為有 SSR
2. spa: 簡單理解為無 SSR
3. generate: 將應用產出為靜態 HTML 頁面,即可作為靜態資源部署至 github-page 等。
Nuxt.js 的特性
1. 以 SFC 構成
2. 代碼分層
3. 服務端渲染
4. 靜態文件服務
5. 強大的路由,除非超複雜的路由,否則不必再寫 router.js
6. 透過 webpack 打包及壓縮 js, css,以及效能優化。
7. HTML 頭部標籤管理 (透過 vue-meta)
8. 支持 hot reload
9. Eslint, Prettier
10. 使用模塊化的方案擴充 Nuxt 應用 (如:gtm, axios, ...)
11. 支持 HTTP/2
12. 支持各種樣式預處理器,例如:scss, less, stylus
...
...
Nuxt.js 提供的元件
1. nuxt
2. nuxt-child
3. nuxt-link
4. no-ssr
What's different Nuxt@2.x ?
1. use Webpack 4
2. ESM is supported everywhere
3. Upgraded to use Babel 7
4. create-nuxt-app
1. 建立一個足夠彈性的新專案
2. 導入你現有的 Node.js 的專案當中
Nuxt.js 可以
Nuxt.js 已經預設好一個 Vue.js 應用,並且提供舒適的開發流程與體驗,使開發者能方便處理 Server-Side Rendering(SSR) 及 SEO 相關問題。
create-nuxt-app
npx? npm? nvm?
npx 是 npm 5.2.0 開始新增的指令,
可以方便開發者避免全域安裝套件。
npx 會臨時安裝 create-nuxt-app,
並完成指令後自動移除,
不會造成 global 的污染。
npx
想用 Nuxt@1.x 怎麼辦?
create-nuxt-app@version
挑戰從 0 到部署
Let's nuxt
Nuxt.js 目錄結構
目錄結構:元件
1. /layouts (使用者模式, 編輯者模式)
2. /pages (路由)
3. /components (UI 元件)
目錄結構:Assets
1. webpack assets (/assets)
=> css-loader, file-loader, url-loader
2. static assets (/static)
目錄結構:模組
1. Modules (/modules)
2. serverMiddleware (/api)
3. Plugins (/plugins)
目錄結構:模組
Modules (/modules)
擴充 nuxt 核心,並於應用啟動時按順序調用"一次"
// nuxt.config.js
module.exports = {
modules: [
'@nuxtjs/axios',
['~/modules/SimpleModule', { key: 'value' }]
],
}
// modules/SimpleModule.js
module.exports = function SimpleModule (moduleOptions) {
// console.log(moduleOptions)
// { key: 'value' }
// console.log(this.options)
// content of nuxt.config.js
}
目錄結構:模組
serverMiddleware (/api)
在 vue-server-render 執行前被調用
// nuxt.config.js
module.exports = {
serverMiddleware: [
'redirect-ssl',
'~/api/logger',
{ path: '/api', handler: '~/api/index.js' }
]
}
// api/logger.js
module.exports = function (req, res, next) {
...
}
目錄結構:模組
Plugins (/plugins)
在 Vue 被實例化前被調用
// nuxt.config.js
module.exports = {
plugins: [
'@/plugins/vuetify',
{ src: '@/plugins/codemirror', ssr: false },
]
}
// plugins/vuetify/index.js
import Vue from 'vue'
import Vuetify from 'vuetify/lib'
import theme from './vuetify.config.js'
Vue.use(Vuetify, {
theme
})
Nuxt.js 設定檔
./nuxt.config.js
Nuxt 部落格的:nuxt.config.js
1. mode
2. head
3. loading
4. css
5. plugins
6. build
7. render
8. router
9. generate
Nuxt.js 2.x 生命週期
nuxtServerInit
一個在 server-side 執行的 action
接收兩個參數
非同步的 nuxtServerInit 需回傳 promise
middleware
1. Global middleware
2. Layout middleware
3. Page middleware
// nuxt.config.js
export default {
router: {
middleware: 'authenticated'
}
}
// layouts/admin.vue
export default {
middleware: 'authenticated'
}
// pages/index.vue
export default {
middleware: 'authenticated'
}
middleware: authenticated
// middleware/authenticated.js
export default function ({ store, redirect }) {
if (!store.state.auth.user) {
return redirect('/admin/login')
}
}
validate(), asyncData(), fetch()
Page components (/pages)
// pages/index.vue
export default {
validate(context) { /* 驗證動態路由是否可用 */
return false // 自動導頁 404 錯誤頁
},
data: vm => ({
name: 'Hunter Liu' // 預設值
}),
asyncData(context) { /* 設置元件 data */
return {
name: 'Sherry Hsu' // 合併回 data
}
},
async fetch ({ store, params }) {
let { data } = await axios.get('http://my-api/stars')
store.commit('setStars', data)
}
}
validate(), asyncData(), fetch()
注意:asyncData(), fetch()
會在 server-side 或 client-side 被執行
// pages/index.vue
export default {
validate(context) { /* 驗證動態路由是否可用 */
return false // 自動導頁 404 錯誤頁
},
data: vm => ({
name: 'Hunter Liu' // 預設值
}),
asyncData(context) { /* 設置元件 data */
return {
name: 'Sherry Hsu' // 合併回 data
}
},
async fetch ({ store, params }) {
let { data } = await axios.get('http://my-api/stars')
store.commit('setStars', data)
}
}
Q&A
Difference between
middleware and serverMiddleware ?
Nuxt 部落格的目錄結構
1. 部落格功能介紹
2. 套件選用與指令介紹
3. Nuxt.js 2.x 簡介, 目錄結構, 設定檔, 生命週期
4. Vuetify 1.3.x 簡介與 vuetify-loader 導入
5. Storybook 4 簡介與導入
6. 部落格: 佈局介紹 (/layouts)
7. 部落格: 所有元件介紹 (/components)
8. Firebase 簡介, 登入, 中間件, 資料庫
9. Vuex store & module registration
10. 部落格: 各頁面介紹 (/pages)
11. 部署 heroku, github pages, firebase hosting
12. 總結
Vuetify
A Material Design Component Framework
Vuetify 和他們有什麼不同?
Element UI
VueStrap
Bootstrap-Vue
Vue Material
...等
Vuetify 是一個基於 Vue 的 UI 框架。
Element UI
VueStrap
Bootstrap-Vue
Vue Material
...等等
比較像 Vue 元件庫
Vuetify 有
- 支援 SSR, PWA, Mobile App
- 支援多國語系
- 大量的元件,class 命名遵循 BEM,容易客製化與複寫樣式
- 優秀的 grid system
- 可自定義 breakpoints 處理 RWD
- 預定義好的全域 class ,避免不斷重複寫樣式
- ......
vuetify@1.3.x
Release at 2018/10/17
開始支援 vuetify-loader
vuetify plugin
/assets/style/app.styl
@require '~vuetify/src/stylus/bootstrap'
$colors = {
"red": $red,
"pink": $pink,
"purple": $purple,
"deep-purple": $deep-purple,
"indigo": $indigo,
"blue": $blue,
"light-blue": $light-blue,
"cyan": $cyan,
"teal": $teal,
"green": $green,
"light-green": $light-green,
"lime": $lime,
"yellow": $yellow,
"amber": $amber,
"orange": $orange,
"deep-orange": $deep-orange,
"brown": $brown,
"blue-grey": $blue-grey,
"grey": $grey,
"shades": $shades
}
@require '~vuetify/src/stylus/app'
/plugins/vuetify/index.js
import Vue from 'vue'
import Vuetify from 'vuetify/lib'
import theme from './vuetify.config.js'
Vue.use(Vuetify, {
theme
})
/plugins/vuetify/vuetify.config.js
export default {
primary: '#41B883',
main: '#121212'
}
vuetify-loader in Nuxt.js
// nuxt.config.js
const VuetifyLoaderPlugin = require('vuetify-loader/lib/plugin')
module.exports = {
css: [
'@/assets/style/app.styl',
],
plugins: [
'@/plugins/vuetify'
],
build: {
extractCSS: true,
transpile: [/^vuetify/],
extend(config, ctx) {
config.plugins.push(
new VuetifyLoaderPlugin()
)
}
}
}
vuetify-loader@1.0.6
tree shaking
自動引入元件
Vuetify@2
- Monorepo
- Core rebuilt from ground up
- Full Typescript support
- Moving from avoriaz to vue test utils
- Moving from Stylus to SCSS
1. 部落格功能介紹
2. 套件選用與指令介紹
3. Nuxt.js 2.x 簡介, 目錄結構, 設定檔, 生命週期
4. Vuetify 1.3.x 簡介與 vuetify-loader 導入
5. Storybook 4 簡介與導入
6. 部落格: 佈局介紹 (/layouts)
7. 部落格: 所有元件介紹 (/components)
8. Firebase 簡介, 登入, 中間件, 資料庫
9. Vuex store & module registration
10. 部落格: 各頁面介紹 (/pages)
11. 部署 heroku, github pages, firebase hosting
12. 總結
Stoybook?
Storybook
- storybook 4
- /.storybook
- storybook@4.x & vuetify@1.3.x
- storybook@4.x & nuxt@2.x
- DEMO
storybook@4.0.0
1. use Webpack 4
2. Upgraded to use Babel 7
Release at 2018/10/29
與 Nuxt@2.x 不謀而合
先看看畫面
/.storybook
- addons.js
- config.js
- preview-head.html
- webpack.config.js
/.storybook/addons.js
import '@storybook/addon-storysource/register'
import 'storybook-readme/register'
import '@storybook/addon-actions/register'
import '@storybook/addon-options/register'
import '@storybook/addon-viewport/register'
/.storybook/config.js
import { configure, addDecorator } from '@storybook/vue'
import { withOptions } from '@storybook/addon-options'
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
Vue.use(Vuetify, {
theme
})
addDecorator(
withOptions({
name: 'nuxt blog',
url: 'https://github.com/hunterliu1003/blog',
addonPanelInRight: true
})
)
const req = require.context('../components', true, /stories\.js$/)
function loadStories() {
req.keys().forEach(filename => req(filename))
}
configure(loadStories, module)
/.storybook/preview-head.html
<!-- Vuetify using material icons -->
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons"
>
<!-- Vuetify using fontawesome icons -->
<link
rel="stylesheet"
href="https://use.fontawesome.com/releases/v5.2.0/css/all.css"
>
/.storybook/webpack.config.js
const path = require("path")
module.exports = (storybookBaseConfig, configType) => {
storybookBaseConfig.module.rules.push({
test: /\.stories\.jsx?$/,
loaders: [require.resolve('@storybook/addon-storysource/loader')],
enforce: 'pre'
})
storybookBaseConfig.module.rules.push({
test: /\.pug$/,
loader: 'pug-plain-loader'
});
storybookBaseConfig.module.rules.push({
test: /\.styl(us)?$/,
use: [
'vue-style-loader',
'css-loader',
'stylus-loader'
]
})
storybookBaseConfig.resolve.alias['@'] = path.dirname(path.resolve(__dirname))
return storybookBaseConfig
}
storybook@4.x & vuetify@1.3.x
// .storybook/config.js
import Vuetify from 'vuetify'
import theme from '@/plugins/vuetify/vuetify.config.js'
import '!!style-loader!css-loader!stylus-loader!../assets/style/app.storybook.styl'
Vue.use(Vuetify, {
theme
})
storybook@4.x & nuxt@2.x
// .storybook/config.js
Vue.component('nuxt-link', {
functional: true,
render: function (createElement, context) {
let allClass = {}
let arrClass = context.data.staticClass
? context.data.staticClass.split(' ')
: []
arrClass.forEach(theClass => {
allClass[theClass] = true
})
return createElement('a', { class: allClass }, context.children)
}
})
Vue.component('no-ssr', {
functional: true,
render (createElement, context) {
return context.children
}
})
Demo
yarn storybook
yarn plop
yarn generate:storybook
cd blog-storybook
now
接下來會是一堆程式碼
1. 部落格功能介紹
2. 套件選用與指令介紹
3. Nuxt.js 2.x 簡介, 目錄結構, 設定檔, 生命週期
4. Vuetify 1.3.x 簡介與 vuetify-loader 導入
5. Storybook 4 簡介與導入
6. 部落格: 佈局介紹 (/layouts)
7. 部落格: 所有元件介紹 (/components)
8. Firebase 簡介, 登入, 中間件, 資料庫
9. Vuex store & module registration
10. 部落格: 各頁面介紹 (/pages)
11. 部署 heroku, github pages, firebase hosting
12. 總結
佈局介紹 (/layouts)
- default.vue
- admin.vue
- error.vue
default: template
default: style
<style lang="stylus">
@import '~vuetify/src/stylus/settings/_variables'
.default-nav
width 350px
padding 20px
position fixed
height 100%
.default-content
padding 40px 30px
margin-left 350px
height 100%
@media $display-breakpoints.md-only
.default-nav
width 300px
.default-content
margin-left 300px
</style>
admin: template
error page
1. 部落格功能介紹
2. 套件選用與指令介紹
3. Nuxt.js 2.x 簡介, 目錄結構, 設定檔, 生命週期
4. Vuetify 1.3.x 簡介與 vuetify-loader 導入
5. Storybook 4 簡介與導入
6. 部落格: 佈局介紹 (/layouts)
7. 部落格: 所有元件介紹 (/components)
8. Firebase 簡介, 登入, 中間件, 資料庫
9. Vuex store & module registration
10. 部落格: 各頁面介紹 (/pages)
11. 部署 heroku, github pages, firebase hosting
12. 總結
所有元件
- TheTags
- TheMarkdown
- ThePostPreview
- FormAddPost
- StoryCentered.vue
元件:TheTags
元件:TheMarkdown
元件:ThePostPreview
使用者模式
元件:ThePostPreview
開發者模式
元件:FormAddPost
元件:StoryCentered
1. 部落格功能介紹
2. 套件選用與指令介紹
3. Nuxt.js 2.x 簡介, 目錄結構, 設定檔, 生命週期
4. Vuetify 1.3.x 簡介與 vuetify-loader 導入
5. Storybook 4 簡介與導入
6. 部落格: 佈局介紹 (/layouts)
7. 部落格: 所有元件介紹 (/components)
8. Firebase 簡介, 登入, 中間件, 資料庫
9. Vuex store & module registration
10. 部落格: 各頁面介紹 (/pages)
11. 部署 heroku, github pages, firebase hosting
12. 總結
firebase
- auth
- firestore
firebase 設定
- ./firebase.json
- ./firestore.indexes.json
- ./firestore.rules
firebase.json
{
...,
"hosting": {
"public": "dist"
},
...
}
firestore.rules
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read
allow write: if request.auth != null;
}
}
}
firebase.indexes.json
{
"indexes": [
{
"collectionId": "posts",
"state": "READY",
"fields": [
{
"fieldPath": "isShow",
"mode": "ASCENDING"
},
{
"fieldPath": "postTime",
"mode": "DESCENDING"
}
]
}
]
}
firebase in Nuxt.js
/plugins/firebase/config.js
export default {
apiKey: "AIzaSyBn1kNP-yxMT4ddncPXsNm46hXYyCWCkXU",
authDomain: "blog-6894c.firebaseapp.com",
databaseURL: "https://blog-6894c.firebaseio.com",
projectId: "blog-6894c",
storageBucket: "blog-6894c.appspot.com",
messagingSenderId: "872777000678"
}
firebase in Nuxt.js
/plugins/firebase/index.js
import firebase from 'firebase/app'
import 'firebase/auth'
import 'firebase/firestore'
import config from './config.js'
!firebase.apps.length ? firebase.initializeApp(config) : ''
const firestore = firebase.firestore()
const settings = {
timestampsInSnapshots: true
}
firestore.settings(settings)
export const auth = firebase.auth()
export const db = firestore
使用 firestore
使用 auth
import { auth } from '@/plugins/firebase'
import { db } from '@/plugins/firebase'
中間件
export default function ({ store, redirect }) {
if (!store.state.auth.user) {
return redirect('/admin/login')
}
}
./middleware/authenticated.js
使用中間件
Page Middleware
export default {
middleware: 'authenticated'
}
1. 部落格功能介紹
2. 套件選用與指令介紹
3. Nuxt.js 2.x 簡介, 目錄結構, 設定檔, 生命週期
4. Vuetify 1.3.x 簡介與 vuetify-loader 導入
5. Storybook 4 簡介與導入
6. 部落格: 佈局介紹 (/layouts)
7. 部落格: 所有元件介紹 (/components)
8. Firebase 簡介, 登入, 中間件, 資料庫
9. Vuex store & module registration
10. 部落格: 各頁面介紹 (/pages)
11. 部署 heroku, github pages, firebase hosting
12. 總結
Vuex module registration
/store/index.js
import Vuex from 'vuex'
import auth from '@/store/modules/auth'
import post from '@/store/modules/post'
import tags from '@/store/modules/tags'
const createStore = () => {
return new Vuex.Store({
modules: {
auth,
post,
tags,
}
})
}
export default createStore
Vuex module registration
/store/modules/index.js
import camelCase from 'lodash/camelCase'
const requireModule = require.context('.', false, /\.js$/)
const modules = {}
requireModule.keys().forEach(fileName => {
// Don't register this file as a Vuex module
if (fileName === './index.js') return
const moduleName = camelCase(
fileName.replace(/(\.\/|\.js)/g, '')
)
modules[moduleName] = {
namespaced: true,
...requireModule(fileName)
}
})
export default modules
Vuex module registration
/store/index.js
import Vuex from 'vuex'
import modules from '@/store/modules'
const createStore = () => {
return new Vuex.Store({
modules
})
}
export default createStore
import Vuex from 'vuex'
import auth from '@/store/modules/auth'
import post from '@/store/modules/post'
import tags from '@/store/modules/tags'
const createStore = () => {
return new Vuex.Store({
modules: {
auth,
post,
tags,
}
})
}
export default createStore
Vuex store
- /store/index.js
- /modules
- /index.js
- /auth.js
- /post.js
- /tags.js
modules/auth.js
- state
- user: null
- mutations
- setUser
- actions
- signInWithEmail
- signOut
- signInAuto
- getters
- authenticated
modules/post.js
-
actions
- addPost
- setPost
- getPostByPostId
- getPostsByPage
- getPostsByTagId
- getPostsAdmin
- getPosts
modules/tags.js
-
actions
- getAllTags
看看程式碼
1. 部落格功能介紹
2. 套件選用與指令介紹
3. Nuxt.js 2.x 簡介, 目錄結構, 設定檔, 生命週期
4. Vuetify 1.3.x 簡介與 vuetify-loader 導入
5. Storybook 4 簡介與導入
6. 部落格: 佈局介紹 (/layouts)
7. 部落格: 所有元件介紹 (/components)
8. Firebase 簡介, 登入, 中間件, 資料庫
9. Vuex store & module registration
10. 部落格: 各頁面介紹 (/pages)
11. 部署 heroku, github pages, firebase hosting
12. 總結
所有路由
使用者模式
- /
- /about
- /posts
- /posts/_postId
- /tags
- /tags/_tagId
- /pages/_pageNum
開發者模式
- /admin
- /admin/_postId
- /admin/addPost
- /admin/login
滿滿的程式碼
1. 部落格功能介紹
2. 套件選用與指令介紹
3. Nuxt.js 2.x 簡介, 目錄結構, 設定檔, 生命週期
4. Vuetify 1.3.x 簡介與 vuetify-loader 導入
5. Storybook 4 簡介與導入
6. 部落格: 佈局介紹 (/layouts)
7. 部落格: 所有元件介紹 (/components)
8. Firebase 簡介, 登入, 中間件, 資料庫
9. Vuex store & module registration
10. 部落格: 各頁面介紹 (/pages)
11. 部署 heroku, github pages, firebase hosting
12. 總結
分享三種部署方法
- Heroku
- Github Page
- Firebase Hosting
部署至 Heroku
// package.json
{
"scripts": {
"heroku-postbuild": "yarn build"
}
}
部署 generate 模式
需要將 nuxt.config.js 的 firestore 註解拿掉
// nuxt.config.js
/* only for scripts generate */
import { db } from './plugins/firebase'
部署至 Github page
yarn generate:github
部署至 Firebase Hosting
yarn generate
firebase deploy
bonus
npm i -g now
或
yarn global add now
storybook
yarn generate:storybook
cd blog-storybook
now
now alias https://blog-storybook-[hash].now.sh blog-storybook
universal 部落格
static 部落格
now
now alias https://hunterliu-blog-[hash].now.sh hunterliu-blog
now scale https://hunterliu-blog.now.sh 1
yarn generate
cd dist
now
now alias https://dist-[hash].now.sh hunterliu-static
1. 部落格功能介紹
2. 套件選用與指令介紹
3. Nuxt.js 2.x 簡介, 目錄結構, 設定檔, 生命週期
4. Vuetify 1.3.x 簡介與 vuetify-loader 導入
5. Storybook 4 簡介與導入
6. 部落格: 佈局介紹 (/layouts)
7. 部落格: 所有元件介紹 (/components)
8. Firebase 簡介, 登入, 中間件, 資料庫
9. Vuex store & module registration
10. 部落格: 各頁面介紹 (/pages)
11. 部署 heroku, github pages, firebase hosting
12. 總結
nuxt.config.js/build
yarn build
yarn analyze
優化:Step by step
優化:splitChunks & http2
// nuxt.config.js
module.exports = {
build: {
optimization: {
splitChunks: {
minSize: 10000,
maxSize: 250000
}
}
},
render: {
http2: {
push: true
}
}
}
優化:lodash tree-shaking
// nuxt.config.js
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin')
module.exports = {
babel: {
plugins: ['lodash']
},
plugins: [new LodashModuleReplacementPlugin]
}
優化:Vuetify tree-shaking
// nuxt.config.js
const VuetifyLoaderPlugin = require('vuetify-loader/lib/plugin')
module.exports = {
plugins: [new VuetifyLoaderPlugin()]
}
Build size 減少約 87kb
縮小 20%
效能如何?
Page: about
Page: login
Page: postId
.nuxt
還記得這張圖嗎?
看看 .nuxt
Q&A
謝謝大家
nuxt-blog
By hunterliu1003
nuxt-blog
- 2,341