mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-18 03:26:57 +02:00
feat(v2): Plugin for Offline/PWA support (#2205)
* implement PWA plugin * added pwa support for docusaurus website * moved sw registration to client module * moved compile function to webpack util * build sw using webpack and render pwa popup * implement @theme/PwaReloadPopup * update website sw to use modules * updated pwa readme * fix header lint errors * apply code formatting * cache files only for mobile, saveData, or installed pwa * added comments about clearing registrations * fixed prettier error * updated pwa README * fix README JS * move /blog => /blog/index.html logic to else branch * add `alwaysPrecache` option * updated docusaurus-plugin-pwa version * added pwa to using-plugins.md * review fixes * re-disable restricted-globals to use self in service worker * useless doc * Update packages/docusaurus-plugin-pwa/README.md Co-authored-by: Reece Dunham <me@rdil.rocks> * Update packages/docusaurus-plugin-pwa/README.md * update a bit pwa doc + minor refactors * minor refactors + add workbox debug mode * env PWA_ prefix * typo * minor refactor * fix file output * add serve:v2:ssl yarn command * minor pwa fixes * typo * add dynamic import comment in SW * comment * let the PWA plugin implement its reload popup on his own * pwa: add Joi options validation * pwa plugin should have its own webpack/babel custom setup * PWA: - debug logs - better SW params system - offline mode activation strategies - docs * add pwa install gif * pwa: popup -> reloadPopup + minor refactors * fix process.env reading + better debug log * minor fixes * minor changes * minor changes Co-authored-by: slorber <lorber.sebastien@gmail.com> Co-authored-by: Sébastien Lorber <slorber@users.noreply.github.com> Co-authored-by: Reece Dunham <me@rdil.rocks>
This commit is contained in:
parent
46f794b2ba
commit
9b3da59886
29 changed files with 1508 additions and 45 deletions
173
packages/docusaurus-plugin-pwa/src/index.js
Normal file
173
packages/docusaurus-plugin-pwa/src/index.js
Normal file
|
@ -0,0 +1,173 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
const LogPlugin = require('@docusaurus/core/lib/webpack/plugins/LogPlugin');
|
||||
const {compile} = require('@docusaurus/core/lib/webpack/utils');
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const {injectManifest} = require('workbox-build');
|
||||
const {PluginOptionSchema} = require('./pluginOptionSchema');
|
||||
const Terser = require('terser-webpack-plugin');
|
||||
|
||||
const isProd = process.env.NODE_ENV === 'production';
|
||||
|
||||
function getSWBabelLoader() {
|
||||
return {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
babelrc: false,
|
||||
configFile: false,
|
||||
presets: [
|
||||
[
|
||||
require.resolve('@babel/preset-env'),
|
||||
{
|
||||
useBuiltIns: 'usage',
|
||||
corejs: '2',
|
||||
// See https://twitter.com/jeffposnick/status/1280223070876315649
|
||||
targets: 'chrome >= 56',
|
||||
},
|
||||
],
|
||||
],
|
||||
plugins: [
|
||||
require.resolve('@babel/plugin-proposal-object-rest-spread'),
|
||||
require.resolve('@babel/plugin-proposal-optional-chaining'),
|
||||
require.resolve('@babel/plugin-proposal-nullish-coalescing-operator'),
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function plugin(context, options) {
|
||||
const {outDir, baseUrl} = context;
|
||||
const {
|
||||
debug,
|
||||
offlineModeActivationStrategies,
|
||||
injectManifestConfig,
|
||||
reloadPopup,
|
||||
pwaHead,
|
||||
swCustom,
|
||||
swRegister,
|
||||
} = options;
|
||||
|
||||
return {
|
||||
name: 'docusaurus-plugin-pwa',
|
||||
|
||||
getThemePath() {
|
||||
return path.resolve(__dirname, './theme');
|
||||
},
|
||||
|
||||
getClientModules() {
|
||||
return isProd ? [swRegister] : [];
|
||||
},
|
||||
|
||||
configureWebpack(config) {
|
||||
if (!isProd) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return {
|
||||
plugins: [
|
||||
new webpack.EnvironmentPlugin({
|
||||
PWA_DEBUG: debug,
|
||||
PWA_SERVICE_WORKER_URL: path.resolve(
|
||||
`${config.output.publicPath || '/'}`,
|
||||
'sw.js',
|
||||
),
|
||||
PWA_OFFLINE_MODE_ACTIVATION_STRATEGIES: offlineModeActivationStrategies,
|
||||
PWA_RELOAD_POPUP: reloadPopup,
|
||||
}),
|
||||
],
|
||||
};
|
||||
},
|
||||
|
||||
injectHtmlTags() {
|
||||
const headTags = [];
|
||||
if (isProd && pwaHead) {
|
||||
pwaHead.forEach(({tagName, ...attributes}) =>
|
||||
headTags.push({
|
||||
tagName,
|
||||
attributes,
|
||||
}),
|
||||
);
|
||||
}
|
||||
return {headTags};
|
||||
},
|
||||
|
||||
async postBuild(props) {
|
||||
if (!isProd) {
|
||||
return;
|
||||
}
|
||||
|
||||
const swSourceFileTest = /\.m?js$/;
|
||||
|
||||
const swWebpackConfig = {
|
||||
entry: path.resolve(__dirname, 'sw.js'),
|
||||
output: {
|
||||
path: outDir,
|
||||
filename: 'sw.js',
|
||||
publicPath: baseUrl,
|
||||
},
|
||||
target: 'webworker',
|
||||
mode: debug ? 'development' : 'production',
|
||||
devtool: debug ? 'source-map' : false,
|
||||
optimization: {
|
||||
splitChunks: false,
|
||||
minimize: !debug,
|
||||
// see https://developers.google.com/web/tools/workbox/guides/using-bundlers#webpack
|
||||
minimizer: [
|
||||
!debug &&
|
||||
new Terser({
|
||||
test: swSourceFileTest,
|
||||
}),
|
||||
].filter(Boolean),
|
||||
},
|
||||
plugins: [
|
||||
new webpack.EnvironmentPlugin({
|
||||
PWA_SW_CUSTOM: swCustom,
|
||||
}),
|
||||
new LogPlugin({
|
||||
name: 'Service Worker',
|
||||
color: 'red',
|
||||
}),
|
||||
],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: swSourceFileTest,
|
||||
exclude: /(node_modules)/,
|
||||
use: getSWBabelLoader(),
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
await compile([swWebpackConfig]);
|
||||
|
||||
const swDest = path.resolve(props.outDir, 'sw.js');
|
||||
|
||||
await injectManifest({
|
||||
...injectManifestConfig,
|
||||
globPatterns: [
|
||||
'**/*.{js,json,css,html}',
|
||||
'**/*.{png,jpg,jpeg,gif,svg,ico}',
|
||||
'**/*.{woff,woff2,eot,ttf,otf}',
|
||||
...(injectManifest.globPatterns || []),
|
||||
],
|
||||
// those attributes are not overrideable
|
||||
swDest,
|
||||
swSrc: swDest,
|
||||
globDirectory: props.outDir,
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = plugin;
|
||||
|
||||
plugin.validateOptions = function validateOptions({validate, options}) {
|
||||
return validate(PluginOptionSchema, options);
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue