咱們都知道pwa是一個新技術.,依靠緩存,離線了還能正常跑,並且秒開。我把之前原生寫的小遊戲遷移到react,再遷移到webpack+react,最後再升級到pwa。具體介紹很少說,咱們開始擼吧。javascript
webpack攻略有不少,不囉嗦了,簡單介紹一些重點。記住幾個點:入口entry、出口output、插件plugins、模塊加載器loader。接下來你一個完整的項目的相關操做至少要包含這些。css
還有一個就是path模塊,專門讀取路徑的,作一切的配置前,首先把路徑搞好吧:html
//通常咱們就是這樣子作的
var path = require("path");
var ROOT_PATH = path.resolve(__dirname);//當前主入口目錄
var SRC_PATH = path.resolve(ROOT_PATH,"src");//src,你寫的代碼在這裏
var DIST_PATH = path.resolve(ROOT_PATH,"dist");//打包結果
var COMP_PATH = path.resolve(SRC_PATH,"component");//vue、react都有的component
//而後咱們的配置裏面
var config = {
mode:'development',
entry: path.resolve(__dirname, './src/index.js'),//webpack把主入口html變成js,而後注入html
output:{
path:DIST_PATH,
filename:"bundle.js"
},
}
複製代碼
模塊加載器,通常咱們不用預處理器的話,繼續在config裏面添加配置,這樣子就基本知足需求vue
module:{
rules:[
{
test:/\.(es6|js)$/,//考慮到es6
use:[
{
loader:"babel-loader",
}
],
exclude:/node_modules/ //不把nodemodules考慮進去
},
{
test:/\.(css)$/,
use:[
{
loader:"style-loader"
},
{
loader:"css-loader"
}
],
exclude:/node_modules/
},
{
test:/\.(png|jpeg|jpg|gif)$/,
use:[
{
loader:"url-loader",
}
],
exclude:/node_modules/
}
]
}
複製代碼
對於插件,咱們通常就用htmlWebpackPlugin和熱更新就差很少了java
plugins:[
new webpack.HotModuleReplacementPlugin(),
new htmlWebpackPlugin({
title: 'game',
template: path.resolve(__dirname, './index.html'),
//bunld.js會注入裏面
inject: true
}),
new OfflinePlugin() //這是pwa用的,等下講到
]
複製代碼
還有一個服務器:node
var server = new WebpackDevServer(webpack(config), {
contentBase: path.resolve(__dirname, './dist'), //默認會以根文件夾提供本地服務器,這裏指定文件夾
historyApiFallback: true, //這是history路由,若是設置爲true,全部的跳轉將指向index.html
port: 9090, //默認8080
publicPath: "/", //本地服務器所加載的頁面所在的目錄
hot: true, //熱更新
inline: true, //實時刷新
historyApiFallback: true //不跳轉
});
server.listen(9090, 'localhost', function (err) {
if (err) throw err
})
複製代碼
哦,對了,列舉一下require清單和package.json:react
var webpack = require("webpack");
var path = require("path");
var htmlWebpackPlugin = require("html-webpack-plugin");
var webpackDelPlugin = require("webpack-del-plugin");
var WebpackDevServer = require('webpack-dev-server');
var ROOT_PATH = path.resolve(__dirname);
var SRC_PATH = path.resolve(ROOT_PATH,"src");
var DIST_PATH = path.resolve(ROOT_PATH,"dist");
var TEM_PATH = path.resolve(SRC_PATH,"component");
var OfflinePlugin = require('offline-plugin')
//package.json
{
"name": "pwawebpack",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"dependencies": {
"jquery": "^3.3.1",
"react-scripts": "1.1.1"
},
"devDependencies": {
"babel-core": "^6.26.3",
"babel-loader": "^7.1.4",
"babel-plugin-react-transform": "^3.0.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"babel-preset-react-hmre": "^1.1.1",
"css-loader": "^0.28.11",
"file-loader": "^1.1.11",
"html-webpack-plugin": "^3.2.0",
"offline-plugin": "^5.0.3",
"react": "^16.3.2",
"react-dom": "^16.3.2",
"react-transform-hmr": "^1.0.4",
"style-loader": "^0.21.0",
"url-loader": "^1.0.1",
"webpack": "^4.8.3",
"webpack-cli": "^2.1.3",
"webpack-del-plugin": "0.0.2",
"webpack-dev-server": "^3.1.4",
"webpack-notifier": "^1.6.0"
},
"scripts": {
"dev": "webpack-dev-server --inline --progress --config webpack.config.js"
}
}
複製代碼
爲了快點看到pwa+webpack的效果,那咱們eslint、test就不寫了jquery
咱們就拿百度到的那些例子說吧,一個正常的pwa,由index.html、一個css、一個manifest.json、一個sw.js。咱們要啓動一個pwa,這是必備的。 其實,是否是看起來有點像谷歌瀏覽器的擴展?有沒有試過本身寫谷歌瀏覽器插件,好比屏蔽廣告的、我的工具的、某些網站收藏夾等等插件。畢竟一家人,因此看起來也有點像。webpack
html:git
<head>
<title>PWA</title>
<meta name="viewport" content="width=device-width, user-scalable=no" />
<link rel="stylesheet" type="text/css" href="main.css">
</head>
<body>
<h1>1</h1>
</body>
複製代碼
manifest.json:其實和本身寫的瀏覽器擴展差很少,就是一些關於名字、樣式、logo的配置
{
"name": "PWA",
"short_name": "p",
"display": "standalone",
"start_url": "/",
"theme_color": "#0000ff",
"background_color": "#00ff00",
"icons": [
{
"src": "logo.png",
"sizes": "256x256",
"type": "image/png"
}
]
}
複製代碼
sw具體介紹 點這裏 生命週期的話,也很少說了,幾個階段:解析Parsed、安裝Installed、激活Activated,中間失敗的話直接跳到廢棄Redundant階段,而後咱們監聽這些事件,咱們直接看效果。
var cacheStorageKey = 'v1'
var cacheList = [
'/',
"index.html",
"main.css",
"logo.png"
]
self.addEventListener('install', e => {
e.waitUntil(
caches.open(cacheStorageKey)
.then(cache => cache.addAll(cacheList))
.then(() => self.skipWaiting())
)
})
self.addEventListener('fetch', function(e) {
e.respondWith(
caches.match(e.request).then(function(response) {
if (response != null) {
return response
}
return fetch(e.request.url)
})
)
})
self.addEventListener('activate', function(e) {
e.waitUntil(
Promise.all(
caches.keys().then(cacheNames => {
return cacheNames.filter(name =>
name !== cacheStorageKey
).map(name=>caches.delete(name))
})
).then(() => {
return self.clients.claim()
})
)
})
複製代碼
注意了,pwa須要https或者localhost,由於這東西能把你本地的文件都拉取了,那也有可能幹其餘事情,因此必須是要在安全的狀況下跑的。還有,是否是發現改了html、js文件,清空緩存都不更新呢?其實改一下sw就能夠了,manifest作應用緩存也是,改個版本號,或者加個空格就行。
文檔見官網
咱們不用配置就能夠跑起來,可是配置裏面有些地方須要注意的並且不能亂改,自行看文檔。配置經常使用的是:caches(默認所有緩存,也能夠本身設置),externals(數組形式,表示其餘資源如cdn),excludes(數組形式,除了哪些不能被緩存),autoUpdate(多久後更新,默認一小時)
咱們使用offline-plugin這個插件,只須要在插件裏面直接引入便可:
plugins: [
// ... 其餘插件
new OfflinePlugin()
]
複製代碼
接着在咱們的入口文件index.js加入:
import * as OfflinePluginRuntime from 'offline-plugin/runtime';
OfflinePluginRuntime.install();
複製代碼
這樣子直接跑webpack就ok了,試一下谷歌瀏覽器offline模式,你會發現仍是能跑: