mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-18 03:26:57 +02:00
* refactor(v2): automatically add base URL to PWA head tags * Add baseUrl only if necessary
178 lines
4.6 KiB
JavaScript
178 lines
4.6 KiB
JavaScript
/**
|
|
* 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')
|
|
.default;
|
|
const {compile} = require('@docusaurus/core/lib/webpack/utils');
|
|
const {normalizeUrl} = require('@docusaurus/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: 'entry',
|
|
corejs: '3',
|
|
// 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.posix.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}) => {
|
|
if (attributes.href && !attributes.href.startsWith(baseUrl)) {
|
|
attributes.href = normalizeUrl([baseUrl, attributes.href]);
|
|
}
|
|
return 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 || '', // fallback value required with Webpack 5
|
|
}),
|
|
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);
|
|
};
|