build-fallback-worker.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. 'use strict'
  2. const path = require('path')
  3. const fs = require('fs')
  4. const webpack = require('webpack')
  5. const { CleanWebpackPlugin } = require('clean-webpack-plugin')
  6. const TerserPlugin = require('terser-webpack-plugin')
  7. const getFallbackEnvs = ({ fallbacks, basedir, id, pageExtensions }) => {
  8. let { document, data } = fallbacks
  9. if (!document) {
  10. let pagesDir = undefined
  11. if (fs.existsSync(path.join(basedir, 'pages'))) {
  12. pagesDir = path.join(basedir, 'pages')
  13. } else if (fs.existsSync(path.join(basedir, 'src', 'pages'))) {
  14. pagesDir = path.join(basedir, 'src', 'pages')
  15. }
  16. if (!pagesDir) return
  17. const offlines = pageExtensions
  18. .map(ext => path.join(pagesDir, `_offline.${ext}`))
  19. .filter(entry => fs.existsSync(entry))
  20. if (offlines.length === 1) {
  21. document = '/_offline'
  22. }
  23. }
  24. if (data && data.endsWith('.json')) {
  25. data = path.posix.join('/_next/data', id, data)
  26. }
  27. const envs = {
  28. __PWA_FALLBACK_DOCUMENT__: document || false,
  29. __PWA_FALLBACK_IMAGE__: fallbacks.image || false,
  30. __PWA_FALLBACK_AUDIO__: fallbacks.audio || false,
  31. __PWA_FALLBACK_VIDEO__: fallbacks.video || false,
  32. __PWA_FALLBACK_FONT__: fallbacks.font || false,
  33. __PWA_FALLBACK_DATA__: data || false
  34. }
  35. if (Object.values(envs).filter(v => !!v).length === 0) return
  36. console.log('> [PWA] Fallback to precache routes when fetch failed from cache or network:')
  37. if (envs.__PWA_FALLBACK_DOCUMENT__) console.log(`> [PWA] document (page): ${envs.__PWA_FALLBACK_DOCUMENT__}`)
  38. if (envs.__PWA_FALLBACK_IMAGE__) console.log(`> [PWA] image: ${envs.__PWA_FALLBACK_IMAGE__}`)
  39. if (envs.__PWA_FALLBACK_AUDIO__) console.log(`> [PWA] audio: ${envs.__PWA_FALLBACK_AUDIO__}`)
  40. if (envs.__PWA_FALLBACK_VIDEO__) console.log(`> [PWA] video: ${envs.__PWA_FALLBACK_VIDEO__}`)
  41. if (envs.__PWA_FALLBACK_FONT__) console.log(`> [PWA] font: ${envs.__PWA_FALLBACK_FONT__}`)
  42. if (envs.__PWA_FALLBACK_DATA__) console.log(`> [PWA] data (/_next/data/**/*.json): ${envs.__PWA_FALLBACK_DATA__}`)
  43. return envs
  44. }
  45. const buildFallbackWorker = ({ id, fallbacks, basedir, destdir, minify, pageExtensions }) => {
  46. const envs = getFallbackEnvs({ fallbacks, basedir, id, pageExtensions })
  47. if (!envs) return
  48. const name = `fallback-${id}.js`
  49. const fallbackJs = path.join(__dirname, `fallback.js`)
  50. webpack({
  51. mode: 'none',
  52. target: 'webworker',
  53. entry: {
  54. main: fallbackJs
  55. },
  56. resolve: {
  57. extensions: ['.js'],
  58. fallback: {
  59. module: false,
  60. dgram: false,
  61. dns: false,
  62. path: false,
  63. fs: false,
  64. os: false,
  65. crypto: false,
  66. stream: false,
  67. http2: false,
  68. net: false,
  69. tls: false,
  70. zlib: false,
  71. child_process: false
  72. }
  73. },
  74. module: {
  75. rules: [
  76. {
  77. test: /\.js$/i,
  78. use: [
  79. {
  80. loader: 'babel-loader',
  81. options: {
  82. presets: [
  83. [
  84. 'next/babel',
  85. {
  86. 'transform-runtime': {
  87. corejs: false,
  88. helpers: true,
  89. regenerator: false,
  90. useESModules: true
  91. },
  92. 'preset-env': {
  93. modules: false,
  94. targets: 'chrome >= 56'
  95. }
  96. }
  97. ]
  98. ]
  99. }
  100. }
  101. ]
  102. }
  103. ]
  104. },
  105. output: {
  106. path: destdir,
  107. filename: name
  108. },
  109. plugins: [
  110. new CleanWebpackPlugin({
  111. cleanOnceBeforeBuildPatterns: [path.join(destdir, 'fallback-*.js'), path.join(destdir, 'fallback-*.js.map')]
  112. }),
  113. new webpack.EnvironmentPlugin(envs)
  114. ],
  115. optimization: minify
  116. ? {
  117. minimize: true,
  118. minimizer: [new TerserPlugin()]
  119. }
  120. : undefined
  121. }).run((error, status) => {
  122. if (error || status.hasErrors()) {
  123. console.error(`> [PWA] Failed to build fallback worker`)
  124. console.error(status.toString({ colors: true }))
  125. process.exit(-1)
  126. }
  127. })
  128. return { fallbacks, name, precaches: Object.values(envs).filter(v => !!v) }
  129. }
  130. module.exports = buildFallbackWorker