Repository: filrak/vue-offline Branch: master Commit: 4b9173333ed9 Files: 7 Total size: 18.1 KB Directory structure: gitextract_h26_jzsc/ ├── .gitignore ├── LICENSE ├── README.md ├── lib/ │ └── vue-offline.js ├── package.json ├── src/ │ └── index.js └── webpack.config.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ .DS_Store node_modules /dist # local env files .env.local .env.*.local # Log files npm-debug.log* yarn-debug.log* yarn-error.log* # Editor directories and files .idea .vscode *.suo *.ntvs* *.njsproj *.sln *.sw* ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright (c) 2018 Filip Rakowski Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # Vue Offline This library allows you to enhance offline capabilities of your Vue.js application. It's especially useful when you're building offline-first Progressive Web Apps or just want to inform your users that they lost internet connection. **TL;DR** Adds `isOnline` `isOffline` data properties, `online`, `offline` events via global mixin and enables offline storage via `Vue.$offlineStorage` based on Local Storage - [Installation](#installation) - [Capabilities](#capabilities) - [VueOfflineMixin](#vueofflinemixin) - [VueOfflineStorage](#vueofflinestorage) Initially made for [Vue Storefront](https://github.com/DivanteLtd/vue-storefront) ## Installation To install this package as a plugin just type: ```` npm install vue-offline --save ```` and add it into your application with ````js import VueOffline from 'vue-offline' Vue.use(VueOffline) ```` ## Capabilities This plugin contains two features: ### VueOfflineMixin Global mixin that'll add following properties to every component in your application: - `isOnline` & `isOffline` data properties ````html ```` ````js export default { name: 'MyComponent', computed: { networkStatus () { return this.isOnline ? 'My network is fine' : 'I am offline' } } } ```` - `online` and `offline` events in every component ````js export default { name: 'MyComponent', mounted () { this.$on('offline', () => { alert('You are offline! The website will not work') }) } } ```` ### Additional configuration By default `VueOfflineMixin` is injected into every component which may be a cause of potential performance problems. You can disable this behavior by setting plugin option `mixin` to `false`. ````js Vue.use(VueOffline, { mixin: false }) ```` You can still make use of `VueOfflineMixin` by injecting it directly into your components: ````js import { VueOfflineMixin } from 'vue-offline' export default { name: 'MyComponent', mixins: [VueOfflineMixin], computed: { networkStatus () { return this.isOnline ? 'My network is fine' : 'I am offline' } }, mounted () { this.$on('offline', () => { alert('You are offline! The website will not work') }) } } ```` ### VueOfflineStorage Offline storage that uses [local storage](https://developer.mozilla.org/pl/docs/Web/API/Window/localStorage) to persist data for offline usage and caching. It's a perfect choice for offline-first PWA. You can use it as a fallback for failed network requests or a local cache. The storage object has following properties: - `set(key, value)` - puts (or updates if already exists) `value` into storage under key `key`. - `get(key)` - returns value stored under key `key` - `keys` - return array of keys existing in your offline storage To use this storage inside your app you can either - use `this.$offlineStorage` from Vue instance property in your components: ````js export default { methods: { getUserData () { if (this.isOnline) { // make network request that returns 'userData' object this.appData = userData this.$offlineStorage.set('user', userData) } else { this.appData = this.$offlineStorage.get('user') } } } } ```` - import the `VueOfflineStorage` instance if you want to use it somewhere else (e.g. Vuex store) ````js import { VueOfflineStorage } from 'vue-offline' const cachedData = VueOfflineStorage.get('cached-data') ```` ### Additional configuration By default `VueofflineStorage` reference is included into every Vue component. You can disable this behavior by setting plugin option `storage` to `false`. ````js Vue.use(VueOffline, { storage: false }) ```` You can still make use of `VueOfflineStorage` by importing it directly into your components: ````js import { VueOfflineStorage } from 'vue-offline' export default { name: 'MyComponent', methods: { getUserData () { if (this.isOnline) { // make network request that returns 'userData' object this.appData = userData VueOfflineStorage.set('user', userData) } else { this.appData = VueOfflineStorage.get('user') } } } } ```` ================================================ FILE: lib/vue-offline.js ================================================ (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define("vue-offline", [], factory); else if(typeof exports === 'object') exports["vue-offline"] = factory(); else root["vue-offline"] = factory(); })(window, function() { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); /******/ } /******/ }; /******/ /******/ // define __esModule on exports /******/ __webpack_require__.r = function(exports) { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ /******/ // create a fake namespace object /******/ // mode & 1: value is a module id, require it /******/ // mode & 2: merge all properties of value into the ns /******/ // mode & 4: return value when already ns object /******/ // mode & 8|1: behave like require /******/ __webpack_require__.t = function(value, mode) { /******/ if(mode & 1) value = __webpack_require__(value); /******/ if(mode & 8) return value; /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; /******/ var ns = Object.create(null); /******/ __webpack_require__.r(ns); /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); /******/ return ns; /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = "./src/index.js"); /******/ }) /************************************************************************/ /******/ ({ /***/ "./src/index.js": /*!**********************!*\ !*** ./src/index.js ***! \**********************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = exports.VueOfflinePlugin = exports.VueOfflineStorage = exports.VueOfflineMixin = void 0; function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } /* ----------------------- Mixin ------------------------ */ /** This mixin adds: * - `isOnline`, `isOffline` data properties * - `online`, `offline` in-component events * */ var VueOfflineMixin = { data: function data() { return { isOnline: false, isOffline: false }; }, mounted: function mounted() { var _this = this; if (typeof window !== 'undefined') { navigator.onLine ? this.isOnline = true : this.isOffline = true; var onlineHandler = function onlineHandler() { _this.$emit('online'); _this.isOnline = true; _this.isOffline = false; }; var offlineHandler = function offlineHandler() { _this.$emit('offline'); _this.isOffline = true; _this.isOnline = false; }; window.addEventListener('online', onlineHandler); window.addEventListener('offline', offlineHandler); this.$once('hook:beforeDestroy', function () { window.removeEventListener('online', onlineHandler); window.removeEventListener('offline', offlineHandler); }); } } }; /* ----------------------- Storage ------------------------ */ exports.VueOfflineMixin = VueOfflineMixin; function _addKey(newKey) { var keys = JSON.parse(localStorage.getItem('VueOfflineStorageKeys')) || []; if (!keys.includes(newKey)) keys.push(newKey); localStorage.setItem('VueOfflineStorageKeys', JSON.stringify(keys)); } /** Offline storage based on localStorage. You can import it and use standalone or register a plugin */ var VueOfflineStorage = { keys: typeof window !== 'undefined' ? localStorage.getItem('VueOfflineStorageKeys') : null, set: function set(key, value) { if (typeof window !== 'undefined') { localStorage.setItem(key, JSON.stringify(value)); _addKey(key); } }, get: function get(key) { return typeof window !== 'undefined' ? JSON.parse(localStorage.getItem(key)) : null; } }; /* ----------------------- Plugin ------------------------ */ /** Registers VueOfflineMixin in whole application giving you access to: * - isOnline, isOffline data properties * - online, offline in-component events */ exports.VueOfflineStorage = VueOfflineStorage; var VueOfflinePlugin = { install: function install(Vue) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var defaultOptions = { mixin: true, storage: true }; var pluginOptions = _objectSpread({}, defaultOptions, options); if (pluginOptions.storage) Vue.prototype.$offlineStorage = VueOfflineStorage; if (pluginOptions.mixin) Vue.mixin(VueOfflineMixin); } }; exports.VueOfflinePlugin = VueOfflinePlugin; var _default = VueOfflinePlugin; exports.default = _default; /***/ }) /******/ }); }); //# sourceMappingURL=vue-offline.js.map ================================================ FILE: package.json ================================================ { "name": "vue-offline", "version": "2.0.8", "description": "Offline states and storage for Vue.js apps and Progressive Web Apps", "main": "lib/vue-offline.js", "scripts": { "build": "webpack --env dev && webpack --env build", "dev": "webpack --progress --colors --watch --env dev" }, "repository": { "type": "git", "url": "https://github.com/filrak/vue-offline.git" }, "keywords": [ "vue", "pwa", "offline", "offline storage" ], "author": "Filip Rakowski", "license": "MIT", "bugs": { "url": "https://github.com/filrak/vue-offline/issues" }, "homepage": "https://github.com/filrak/vue-offline", "devDependencies": { "@babel/cli": "^7.0.0-beta.51", "@babel/core": "^7.0.0-beta.51", "@babel/preset-env": "^7.0.0-beta.51", "babel-eslint": "^8.0.3", "babel-loader": "^8.0.0-beta.4", "babel-plugin-add-module-exports": "^0.2.1", "babel-preset-env": "^7.0.0-beta.3", "babel-register": "^7.0.0-beta.3", "chai": "^4.1.2", "eslint": "^5.0.1", "eslint-loader": "^2.0.0", "jsdom": "11.11.0", "jsdom-global": "3.0.2", "mocha": "^4.0.1", "uglifyjs-webpack-plugin": "^1.2.7", "webpack": "^4.12.2", "webpack-cli": "^3.0.8", "yargs": "^10.0.3" } } ================================================ FILE: src/index.js ================================================ /* ----------------------- Mixin ------------------------ */ /** This mixin adds: * - `isOnline`, `isOffline` data properties * - `online`, `offline` in-component events * */ export const VueOfflineMixin = { data () { return { isOnline: false, isOffline: false } }, mounted () { if (typeof window !== 'undefined') { navigator.onLine ? this.isOnline = true : this.isOffline = true const onlineHandler = () => { this.$emit('online') this.isOnline = true this.isOffline = false } const offlineHandler = () => { this.$emit('offline') this.isOffline = true this.isOnline = false } window.addEventListener('online', onlineHandler) window.addEventListener('offline', offlineHandler) this.$once('hook:beforeDestroy', () => { window.removeEventListener('online', onlineHandler) window.removeEventListener('offline', offlineHandler) }) } } } /* ----------------------- Storage ------------------------ */ function _addKey (newKey) { let keys = JSON.parse(localStorage.getItem('VueOfflineStorageKeys')) || [] if (!keys.includes(newKey)) keys.push(newKey) localStorage.setItem('VueOfflineStorageKeys', JSON.stringify(keys)) } /** Offline storage based on localStorage. You can import it and use standalone or register a plugin */ export const VueOfflineStorage = { keys: typeof window !== 'undefined' ? localStorage.getItem('VueOfflineStorageKeys') : null, set (key, value) { if ( typeof window !== 'undefined' ) { localStorage.setItem(key, JSON.stringify(value)) _addKey(key) } }, get (key) { return typeof window !== 'undefined' ? JSON.parse(localStorage.getItem(key)) : null } } /* ----------------------- Plugin ------------------------ */ /** Registers VueOfflineMixin in whole application giving you access to: * - isOnline, isOffline data properties * - online, offline in-component events */ export const VueOfflinePlugin = { install (Vue, options = {}) { const defaultOptions = { mixin: true, storage: true }; const pluginOptions = { ...defaultOptions, ...options } if (pluginOptions.storage) Vue.prototype.$offlineStorage = VueOfflineStorage if (pluginOptions.mixin) Vue.mixin(VueOfflineMixin) } } export default VueOfflinePlugin ================================================ FILE: webpack.config.js ================================================ /* global __dirname, require, module*/ const webpack = require('webpack'); const path = require('path'); const env = require('yargs').argv.env; // use --env with webpack 2 const pkg = require('./package.json'); let libraryName = pkg.name; let outputFile, mode; if (env === 'build') { mode = 'production'; outputFile = libraryName + '.min.js'; } else { mode = 'development'; outputFile = libraryName + '.js'; } const config = { mode: mode, entry: __dirname + '/src/index.js', devtool: 'source-map', output: { path: __dirname + '/lib', filename: outputFile, library: libraryName, libraryTarget: 'umd', umdNamedDefine: true }, module: { rules: [ { test: /(\.jsx|\.js)$/, loader: 'babel-loader', options: { presets: ['@babel/preset-env'] }, exclude: /(node_modules|bower_components)/ } ] }, resolve: { modules: [path.resolve('./node_modules'), path.resolve('./src')], extensions: ['.json', '.js'] } }; module.exports = config;