漸進式Web應用是大勢所趨。越來越多的大公司開始使用這些技術(比如Twitter:https://mobile.twitter.com/)。
想象當你在地鐵中瀏覽一個Web應用的時候,這個應用通過推送通知、提供實時資料、以及提供類似於APP的導航,讓你沉浸其中。這些就是PWA的神奇所在。
漸進式Web應用(PWA)是一種能夠提供給使用者類似於APP的體驗的Web應用。PWA得益於現代Web科技的創新(Service Workers, Native APIS, JS famework),它可以提升的Web應用的質量標準。
如果你想了解更多關於PWA的資訊,請訪問這個很棒的網站Google developer page。
看一下下面的PWA!看起來很像原生的APP,是不是?
Twitter漸進式Web應用
從開發者的角度來看,PWA相比於原生應用擁有巨大的優點。它基本上就是一個網站,因此:
- 你可以選擇任何你喜歡的框架來進行開發;
- 一段程式碼搞定一切:它可以跨平臺、跨裝置(程式碼是通過使用者的瀏覽器執行的);
- 易於傳播:不需要通過應用商店來下載。
然而,在2017年早期,PWA仍然面臨一些限制條件:
- Safari不支援一些基本的PWA特性,比如 Service workers,但是蘋果公司似乎已經準備開始著手處理了;
- 一些原生的函式依然沒有得到支援:可以瀏覽這個頁面What web can do 獲得更多資訊。
教程目標
本教程的目標是利用VueJS以及Webpack從頭建立一個基礎但完整的漸進式Web應用。我們的應用將會滿足介紹裡面的所有需求:漸進式的,響應式的,連線獨立的等等。我想大致讓你看看PWA能夠實現些什麼:流暢的類原生應用,離線行為,原生特性介面,推送通知。
為了讓事情有些挑戰性,我們打算構建一個貓咪圖片交流app:CropChat!CropChat使用者能夠瀏覽貓咪照片流,點選圖片之後可以開啟這個貓咪的詳情介紹,使用者也可以釋出新的貓咪圖片(圖片資源可以是來自網際網路,來自裝置圖片庫或通過照相機拍攝的)。
這個教程將會分為幾個部分:
- [Part 1] 建立一個基於VueJS, Webpack 以及Material Design Lite的單頁面應用
- [Part 2] 基於Vue-Resource以及VueFire將App和遠端的API進行連線
- [Part 3] 利用Service Worker來實現離線模式
- [Part 4] 訪問裝置照相機進行拍照
- [Part 5] 訪問裝置驅動上傳圖片
- [Part 6] 實現推送通知
- [Part 7] 訪問裝置地址
我們的PWA的基本元件
我們的漸進式Web應用是基於你喜歡的現代元件!
- VueJS 2檢視層: 利用Material Design Lite來渲染檢視
- Vue-Router:處理單頁應用的路由
- Vue-Resource & Vuefire: 處理和Firebase資料庫的通訊
- Service Worker:處理離線模式並且保持資料更新
- Webpack & Vue-loader:構建我們的應用,提供熱載入、ES2016 和 前處理器。
讓我們開始第一部分吧!
[PART 1] 建立一個基於VueJS, Webpack 以及Material Design Lite的單頁面應用
如果你不熟悉VueJS 2,我強烈建議你閱讀官方教程。
構建VueJS APP基礎
我們打算利用Vue-cli來建立我們的應用:
1 |
npm install -g vue-cli |
Vue-cli自帶一些模板。我們將會選擇Webpack模板。Webpack是一個用於JavaScript應用的現代模組打包工具,它能夠處理並且構建我們的資源。Vue-cli將使用Webpack,vue-loader(熱載入!),JS linter以及測試套件來建立一個虛擬的VueJS應用。
1 |
vue init webpack cropchat |
你可能需要回答一些問題,下面是我使用過的配置:
1 |
This will install Vue 2.x version of the template. |
1 |
For Vue 1.x use: vue init webpack#1.0 cropchat |
1 2 3 4 5 6 7 8 9 |
? Project name cropchat ? Project description Image messenging application ? Author Charles BOCHET ? Vue build standalone ? Install vue-router? Yes ? Use ESLint to lint your code? Yes ? Pick an ESLint preset Standard ? Setup unit tests with Karma + Mocha? Yes ? Setup e2e tests with Nightwatch? No |
1 |
vue-cli · Generated "cropchat". |
這個過程會建立一個包含以下子資料夾的專案資料夾:
- build: 包含Webpack以及vue-loader配置檔案
- config: 包含我們的APP配置(環境,引數等等)
- src: 我們應用的原始碼
- static: 圖片,css以及其它的公共資源
- test: 通過Karma & Mocha建立的單元測試檔案
然後執行:
1 2 3 |
cd cropchat npm install npm run dev |
這將會在你的瀏覽器開啟localhost:8080
:
通過新增一個合適的Manifest讓它可以進行安裝:
PWA的最大優點之一就是容易安裝並且分享,下面我們就開始著手做吧!
為了這樣做,我們需要新增一個manifest.json檔案並且在index.html檔案中進行宣告。
pwa-manifest-webpack-plugin
這個包支援應用構建的時候生成這個檔案:
1 |
npm i pwa-manifest-webpack-plugin --save |
接著我們通過編輯build/webpack.dev.conf.js
和 build/webpack.prod.conf.js
來更新構建過程。
在檔案的頂部引入pwa-manifest-webpack-plugin
:
1 2 |
var path = require('path') var manifestPlugin = require('pwa-manifest-webpack-plugin') |
並且將它新增到外掛:
1 2 3 4 5 6 7 8 9 10 |
plugins: [ new manifestPlugin({ name: 'CropChat', description: 'CropChat - Image Messenger Application', display: 'fullscreen', icon: { src: path.resolve('src/assets/logo.png'), sizes: [200] } }), |
最後,在 index.html
中宣告使用manifest.json
:
1 2 |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="manifest" href="./manifest.json"> |
你可能需要重啟你的應用:可以通過殺死之前的程式並再次執行:
1 |
npm run dev |
成功了!接下來讓我們嘗試下在手機裝置上安裝CropChat!想要從遠端手機裝置上訪問localhost:8080
有許多方式,我最喜歡就是使用ngrok。
Ngrok是一種支援遠端登入您的本地環境的免費服務。
安裝ngrok:
1 |
npm install -G ngrok |
接著,執行:
1 |
ngrok http 8080 |
那應該你將看到以下輸出:
1 2 3 4 5 6 7 8 9 10 11 |
ngrok by @inconshreveable (Ctrl+C to quit) Session Status online Version 2.1.18 Region United States (us) Web Interface http://127.0.0.1:4040 Forwarding http://5ef29506.ngrok.io -> localhost:8080 Forwarding https://5ef29506.ngrok.io -> localhost:8080 Connections ttl opn rt1 rt5 p50 p90 39 3 0.01 0.01 120.01 881.89 |
使用你的手機訪問 http://5ef29506.ngrok.io
,你就能夠在你的手機桌面上新增CropChat這個APP了。
Cropchat的原始碼能夠在GitHub here上看到。這個教程中的每一個部分都能夠在Git的歷史記錄裡找到: 5ff77fd3cd71a988fad9c187d57e87ea80d670f0 這個commit就是教程的第一部分。
想了解更多關於ngrok的資訊,你可以閱讀Matthieu Auger的文章:Expose your local environment to the world with ngrok
建立檢視框架和處理路由
既然我們已經打好了基礎,接下來我們就開始著手實現CropChat的功能。CropChat具有三個檢視:
- Home View: 展示貓咪的圖片列表
- Detail View: 展示某個貓咪圖片的詳情(通過點選Home View進入)
- Post View: 允許使用者上傳一張新的圖片
建立src/component/HomeView.vue
,這個檢視有如下的結構:
1 2 3 4 |
<template> <ul class="list"> </ul> </template> |
1 2 3 4 |
<script> export default { } </script> |
1 2 3 4 5 6 |
<style scoped> .list { width: 100%; padding: 0; } </style> |
src/component/DetailView.vue
的結構:
1 2 3 4 |
<template> <div class="card-image"> </div> </template> |
1 2 3 4 |
<script> export default { } </script> |
1 2 |
<style scoped> </style> |
src/component/PostView.vue
的結構:
1 2 3 4 5 |
<template> <div class="waiting"> Not yet available </div> </template> |
1 2 3 4 |
<script> export default { } </script> |
1 2 3 4 5 6 |
<style scoped> .waiting { padding: 10px; color: #555; } </style> |
最終,更新路由檔案 src/router/index.js
:
1 2 3 4 5 |
import Vue from 'vue' import Router from 'vue-router' import HomeView from 'components/HomeView' import DetailView from 'components/DetailView' import PostView from 'components/PostView' |
1 |
Vue.use(Router) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
export default new Router({ routes: [ { path: '/', name: 'home', component: HomeView }, { path: '/detail/:id', name: 'detail', component: DetailView }, { path: '/post', name: 'post', component: PostView } ] }) |
刪除沒有用的Hello.vue這個檢視之後,你應該能夠直接看到你手機上的這個APP的變化了(熱載入是不是很棒呀?)
Git commit: 22ab9a2058dae8f7689b8635ff52d89652675aa6
安裝 Material Design Lite
你還不知道Material Design Lite?它是一個輕量級的並且容易在你的Web應用上實現Material Design 的框架。
你可以在這看到更多的文件:Get MDL.io
更新CropChat的依賴:
1 |
npm install material-design-lite --save |
更新src/App.vue
來匯入MDL樣式並且載入MDL模組:
1 2 3 4 |
<script> require('material-design-lite') ... </script> |
1 2 3 4 |
<style> @import url('https://fonts.googleapis.com/icon?family=Material+Icons'); @import url('https://code.getmdl.io/1.2.1/material.blue-red.min.css'); </style> |
Git commit: b726b40488132c400dd861bd397f61b15e81631e
為你的單頁面應用提供一個導航欄:
更新主要元件src/App.vue
中的模板部分:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<template> <div class="mdl-layout mdl-js-layout mdl-layout--fixed-header"> <header class="mdl-layout__header"> <div class="mdl-layout__header-row"> <span class="mdl-layout-title">CropChat</span> </div> </header> <div class="mdl-layout__drawer"> <span class="mdl-layout-title">CropChat</span> <nav class="mdl-navigation"> <a class="mdl-navigation__link" href="/#/" @click="hideMenu">Home</a> <a class="mdl-navigation__link" href="/#/post" @click="hideMenu">Post a picture</a> </nav> </div> <main class="mdl-layout__content"> <div class="page-content"> <router-view></router-view> </div> </main> </div> </template> |
由於Material Design Lite不是專門為單頁應用而設計的,因此在使用者點選選單連結的時候我們需要隱藏burger選單:
1 2 3 4 5 6 7 8 9 10 11 12 |
<script> ... export default { name: 'app', methods: { hideMenu: function () { document.getElementsByClassName('mdl-layout__drawer')[0].classList.remove('is-visible') document.getElementsByClassName('mdl-layout__obfuscator')[0].classList.remove('is-visible') } } } </script> |
Git commit: 829d0af767a9f7cba13355296d9da79384d80099
豐富我們的檢視並讓應用跑起來
因為還沒有連線一個後臺伺服器,所以我們現在打算暫時使用假資料。
建立一個src/data.js
檔案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
export default { pictures: [ { 'id': 0, 'url': 'http://25.media.tumblr.com/tumblr_m40h4ksiUa1qbyxr0o1_400.gif', 'comment': 'A cat game', 'info': 'Posted by Kevin on Friday' }, { 'id': 1, 'url': 'http://25.media.tumblr.com/tumblr_lhd7n9Qec01qgnva2o1_500.jpg', 'comment': 'Tatoo & cat', 'info': 'Posted by Charles on Tuesday' }, { 'id': 2, 'url': 'http://24.media.tumblr.com/tumblr_m4j2atctRm1qejbiro1_1280.jpg', 'comment': 'Santa cat', 'info': 'Posted by Richard on Monday' }, { 'id': 3, 'url': 'http://25.media.tumblr.com/tumblr_m3rmbwhVB51qhwmnpo1_1280.jpg', 'comment': 'Mexico cat', 'info': 'Posted by Richard on Monday' }, { 'id': 4, 'url': 'http://24.media.tumblr.com/tumblr_mceknxs4Lo1qd477zo1_500.jpg', 'comment': 'Curious cat', 'info': 'Posted by Richard on Monday' } ] } |
在HomeView.vue
的script部分中匯入資料並且將圖片連結到對應的詳情頁:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<script> import data from '../data' export default { methods: { displayDetails (id) { this.$router.push({ name: 'detail', params: { id: id }}) } }, data () { return { 'pictures': data.pictures } } } </script> |
更新HomeView.vue
模板和樣式:
對DetailView.vue
進行同樣的操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<template> <div class="mdl-grid"> <div class="mdl-cell mdl-cell--8-col"> <div class="picture"> <img :src="this.$data.pictures[$route.params.id].url" /> </div> <div class="info"> <span>{{ this.$data.pictures[$route.params.id].info }}</span> </div> </div> <div class="mdl-cell mdl-cell--4-col mdl-cell--8-col-tablet"> <div class="comment"> <span>{{ this.$data.pictures[$route.params.id].comment }}</span> </div> <div class="actions"> <a class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored" href="/#/post"> ANSWER </a> </div> </div> </div> </template> |
1 2 3 4 5 6 7 8 9 10 |
<script> import data from '../data' export default { data () { return { 'pictures': data.pictures } } } </script> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<style scoped> .picture > img { color: #fff; width:100%; } .info { text-align: right; padding: 5px; color: #555; font-size: 10px; } .comment { padding: 10px; color: #555; } .actions { text-align: center; } </style> |
Git commit: 39360f251da153c780cd148dc3cf234348bb1e87
關於’href’連結的使用:我推薦你使用VueJS的元件,但是在這個教程裡我想使程式碼儘可能的簡單。
最後的結果
我們完成了,CropChat完成啦!
原始碼放在了這個 GitHub 倉庫裡: https://github.com/charlesBochet/vueJSPwa
總結
我相信通過這個教程你已經有能力能夠很輕鬆地使用VueJS和Webpack來建立一個web應用,總結一下:
- Vue-cli用過僅僅一行命令來建立一個VueJS + Webpack應用
- 通過新增Manifest.json檔案讓你的web應用能夠安裝
- 使用Vue-Router以及Material Design來建立一個類app使用者體驗的應用
然而,CropChat 還依然不是一個漸進式 Web 應用:讓我們看一下PWA的需求清單:
啊,還有一半的目標沒有實現!那麼在接下來的幾部分中,我們將完成這些目標,敬請期待!