webpack.config.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /**
  2. * Build config for the v0.5.0 FSE migration (@wordpress/scripts + webpack).
  3. *
  4. * This is now the theme's only build — it fully replaced the old gulp pipeline
  5. * (copy/mixin/build/cssf/js/jsf). It compiles the site-wide stylesheet and both
  6. * JS bundles from npm packages + the bespoke source in src/ (see
  7. * _claude/notes/upgrade-plan.md).
  8. *
  9. * Output layout (output.path = theme root so nothing escapes it):
  10. * - front → js/v4-front.min.js (homepage bundle, overwrites the enqueued path)
  11. * - main → js/v4-script.min.js (site-wide bundle, overwrites the enqueued path)
  12. * - v4-style → v4-style.min.css (theme root — keeps the `style-min` enqueue + font url()s valid)
  13. * - index / other → build/[name].{js,css} (seed + future block view scripts)
  14. */
  15. const path = require('path');
  16. const webpack = require('webpack');
  17. const MiniCssExtractPlugin = require('mini-css-extract-plugin');
  18. const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
  19. const BrowserSyncPlugin = require('browser-sync-webpack-plugin');
  20. module.exports = {
  21. entry: {
  22. index: './src/index.js',
  23. // Reproduces gulp `build` → v4-style.min.css (concat of the 5 CSS sources, in order).
  24. 'v4-style': './src/legacy-style.js',
  25. // Reproduces gulp `jsf` → homepage JS (jquery + svg-morpheus + front-page.js).
  26. front: './src/front.js',
  27. // Reproduces gulp `js` → site-wide JS (jquery/bootstrap/plugins).
  28. main: './src/main.js',
  29. // FullCalendar — split out of the site-wide bundle; enqueued only on the About page.
  30. 'v4-fullcalendar': './src/fullcalendar.js',
  31. },
  32. output: {
  33. path: path.resolve(__dirname), // theme root
  34. // The two bundles overwrite their committed, enqueued paths in place (like
  35. // v4-style.min.css does) so nothing needs re-pointing and they ship via git.
  36. // Everything else (the seed, future block scripts) goes under the gitignored build/.
  37. filename: (pathData) => {
  38. const n = pathData.chunk.name;
  39. if (n === 'front') return 'js/v4-front.min.js';
  40. if (n === 'main') return 'js/v4-script.min.js';
  41. if (n === 'v4-fullcalendar') return 'js/v4-fullcalendar.min.js';
  42. return 'build/[name].js';
  43. },
  44. clean: false, // NEVER clean — output.path is the theme root
  45. },
  46. module: {
  47. rules: [
  48. {
  49. test: /\.js$/,
  50. exclude: /node_modules/,
  51. use: { loader: 'babel-loader' },
  52. },
  53. {
  54. // svg-morpheus ships a bare global `var SVGMorpheus` (no export) — surface it as a
  55. // module export so src/front.js can re-expose it on window for front-page.js.
  56. test: require.resolve('svg-morpheus/compile/minified/svg-morpheus.js'),
  57. loader: 'exports-loader',
  58. options: { type: 'commonjs', exports: 'single SVGMorpheus' },
  59. },
  60. {
  61. // fullcalendar/main.js is likewise a bare global `var FullCalendar` build.
  62. test: require.resolve('fullcalendar/main.js'),
  63. loader: 'exports-loader',
  64. options: { type: 'commonjs', exports: 'single FullCalendar' },
  65. },
  66. {
  67. test: /\.css$/,
  68. use: [
  69. MiniCssExtractPlugin.loader,
  70. // url:false / import:false → leave url() + @import untouched (gulp-concat parity,
  71. // so the relative `fonts/…` paths keep resolving from the theme root).
  72. { loader: 'css-loader', options: { url: false, import: false } },
  73. ],
  74. },
  75. {
  76. // styles.scss @imports Bootstrap + bootstrap-icons from node_modules — webpack
  77. // now compiles it (replaces gulp's `mixin` task). quietDeps silences Bootstrap's
  78. // internal sass deprecation noise; url:false keeps the bootstrap-icons font path.
  79. test: /\.scss$/,
  80. use: [
  81. MiniCssExtractPlugin.loader,
  82. { loader: 'css-loader', options: { url: false, import: false } },
  83. {
  84. loader: 'sass-loader',
  85. options: {
  86. implementation: require('sass'),
  87. sassOptions: { quietDeps: true },
  88. },
  89. },
  90. ],
  91. },
  92. ],
  93. },
  94. optimization: {
  95. // '...' keeps webpack's default JS minifier (terser); add CSS minification.
  96. minimizer: [
  97. '...',
  98. // discardComments.removeAll matches the old gulp clean-css (specialComments:0).
  99. new CssMinimizerPlugin({
  100. minimizerOptions: { preset: ['default', { discardComments: { removeAll: true } }] },
  101. }),
  102. ],
  103. },
  104. plugins: [
  105. // jQuery globals for the bundled source that assumes a global $ (front-page.js
  106. // IIFEs, and the npm jQuery plugins validation/backstretch/lazyload in the main bundle).
  107. new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery' }),
  108. new MiniCssExtractPlugin({
  109. filename: ({ chunk }) =>
  110. chunk.name === 'v4-style' ? 'v4-style.min.css' : 'build/[name].css',
  111. }),
  112. new BrowserSyncPlugin({
  113. host: 'daw.stu',
  114. port: 81,
  115. proxy: 'https://daw.stu',
  116. https: {
  117. key: '/opt/homebrew/etc/httpd/ssl/daw.stu-key.pem',
  118. cert: '/opt/homebrew/etc/httpd/ssl/daw.stu-cert.pem',
  119. },
  120. files: [
  121. './**/*.php',
  122. './src/**/*.js',
  123. './src/**/*.css',
  124. './templates/**/*.html',
  125. './parts/**/*.html',
  126. './patterns/**/*.php',
  127. './theme.json',
  128. ],
  129. ignore: ['node_modules', 'build', 'js/v4-*', '*.min.*'],
  130. open: 'external',
  131. reloadDelay: 50,
  132. injectChanges: true,
  133. notify: false,
  134. // Serve dev responses uncached so a reload always reflects the latest edit
  135. // (no stale browser cache while iterating). Pairs with the `files` watch above,
  136. // which already auto-reloads on .php / template / src changes.
  137. middleware: function (req, res, next) {
  138. res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0');
  139. res.setHeader('Pragma', 'no-cache');
  140. res.setHeader('Expires', '0');
  141. next();
  142. },
  143. }),
  144. ],
  145. };