Настройка вашего сервисного работника с помощью Create React App возможна, но может быть довольно сложной и хакерской.
Из коробки CRA использует Workbox GenerateSW плагин webpack для генерации service-worker.js
файл, и вы не можете внедрить в него какой-либо код (вы могли бы с CRA @ 1, а не с CRA @ 2)
У вас есть несколько стратегий, я начну спростейший.
Решение 1: предоставьте свой собственный файл работника службы
- в
src/index.js
включите работника службы: // serviceWorker.unregister()
serviceWorker.register()
в src/serviceWorker.js
зарегистрируйте свой пользовательский файл:
// if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
if ('serviceWorker' in navigator) {
// const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
const swUrl = `${process.env.PUBLIC_URL}/custom-service-worker.js`;
При запуске сервера dev необходимо изменить имя причины, CRA предоставляет mock для service-worker.js
в папке public/
, создайте файл custom-service-worker.js
.Webpack скопирует его как в папку build/
Плюсы : быстрый, грязный выигрыш
Минусы : ваш пользовательский файл не обрабатывается с помощью Webpack (без импорта), и вы должны самостоятельно реализовать логику сетевого кэширования (при условии, что вам нужен PWA), поскольку выобходят плагины Workbox
Решение 2: добавьте свой код к сгенерированному сервис-работнику
Для него есть модуль: cra-append-sw .Вы отвечаете за предоставление прилагаемого кода.
Плюсы : простота настройки, преимущества Преимущества GenerateSW
Минусы: добавленный код обрабатывается с помощью Babel / Webpack, но без использования конфигурации CRA (вы можете отказаться).Все еще используйте GenerateSW, который обрабатывает сетевое кэширование для вас.Не уверен, что он работает при локальной разработке
Решение 3: используйте Workbox в пользовательском файле служебного рабочего
примените первые 2 шага решения № 1: измените src/index.js
и src/serviceWorker.js
в папке src/
, создайте файл custom-service-worker.js
.Он будет обрабатываться Webpack, поэтому вы можете использовать синтаксис ES2016 / TypeScript и модули импорта
/* eslint no-restricted-globals: "off" */
import * as precaching from 'workbox-precaching'
// your own imports
if (self.__precacheManifest) {
precaching.precacheAndRoute(self.__precacheManifest)
}
// your own code
установить реагировать на изменения в приложениях :
npm add --save-dev react-app-rewired
- в
package.json
, в "scripts"
, замените react-scripts
на react-app-rewired
настройка веб-пакета настройки: создать config-overrides.js
в корневой папке:
const WebpackBeforeBuildPlugin = require('before-build-webpack')
const WorkboxWebpackPlugin = require('workbox-webpack-plugin')
const path = require('path')
const merge = require('lodash.merge')
const fs = require('fs')
// from https://www.viget.com/articles/run-multiple-webpack-configs-sequentially/
class WaitPlugin extends WebpackBeforeBuildPlugin {
constructor(file, interval = 100, timeout = 60e3) {
super(function(stats, callback) {
const start = Date.now()
function poll() {
if (fs.existsSync(file)) {
callback()
} else if (Date.now() - start > timeout) {
throw Error(`Couldn't access ${file} within ${timeout}s`)
} else {
setTimeout(poll, interval)
}
}
poll()
})
}
}
const swOutputName = 'custom-service-worker.js'
const workerSource = path.resolve(__dirname, 'src', swOutputName)
module.exports = {
webpack: (config, env) => {
// we need 2 webpack configurations:
// 1- for the service worker file.
// it needs to be processed by webpack (to include 3rd party modules), and the output must be a
// plain, single file, not injected in the HTML page
const swConfig = merge({}, config, {
name: 'service worker',
entry: workerSource,
output: {
filename: swOutputName
},
optimization: {
splitChunks: false,
runtimeChunk: false
}
})
delete swConfig.plugins
// 2- for the main application.
// we'll reuse configuration from create-react-app, without a specific Workbox configuration,
// so it could inject workbox-precache module and the computed manifest into the BUILT service-worker.js file.
// this require to WAIT for the first configuration to be finished
if (env === 'production') {
const builtWorkerPath = path.resolve(config.output.path, swOutputName)
config.name = 'main-application'
config.plugins.push(
new WorkboxWebpackPlugin.InjectManifest({
swSrc: builtWorkerPath,
swDest: swOutputName
}),
new WaitPlugin(builtWorkerPath)
)
}
// remove Workbox service-worker.js generator
const removed = config.plugins.findIndex(
({ constructor: { name } }) => name === 'GenerateSW'
)
if (removed !== -1) {
config.plugins.splice(removed, 1)
}
const result = [swConfig, config]
// compatibility hack for CRA's build script to support multiple configurations
// https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/scripts/build.js#L119
result.output = { publicPath: config.output.publicPath }
return result
}
}
Pros : вы можете использовать код ES2016 / TypeScript в файле сервисного работника,Вы по-прежнему пользуетесь возможностями сетевого кэширования Workbox с полным контролем над ним
Минусы : сложные и хрупкие, из-за множественного взлома конфигурации.
Я использовал последнее решение, потому что мне требовался как кеширующий код из Workbox, так и немного import
в моем файле рабочего сервиса.
act-app-rewire-workbox может помочь упроститьконфигурация Webpack (одна для основного приложения).Быть проверенным.