pwa+webpack,初探與踩坑

0.前言

咱們都知道pwa是一個新技術.,依靠緩存,離線了還能正常跑,並且秒開。我把之前原生寫的小遊戲遷移到react,再遷移到webpack+react,最後再升級到pwa。具體介紹很少說,咱們開始擼吧。javascript

1.webpack

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

2.pwa

咱們就拿百度到的那些例子說吧,一個正常的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作應用緩存也是,改個版本號,或者加個空格就行。

3.基於webpack的pwa

文檔見官網

咱們不用配置就能夠跑起來,可是配置裏面有些地方須要注意的並且不能亂改,自行看文檔。配置經常使用的是:caches(默認所有緩存,也能夠本身設置),externals(數組形式,表示其餘資源如cdn),excludes(數組形式,除了哪些不能被緩存),autoUpdate(多久後更新,默認一小時)

咱們使用offline-plugin這個插件,只須要在插件裏面直接引入便可:

plugins: [
    // ... 其餘插件
    new OfflinePlugin()
  ]
複製代碼

接着在咱們的入口文件index.js加入:

import * as OfflinePluginRuntime from 'offline-plugin/runtime';
OfflinePluginRuntime.install();
複製代碼

這樣子直接跑webpack就ok了,試一下谷歌瀏覽器offline模式,你會發現仍是能跑:

1
相關文章
相關標籤/搜索