|
1 | | -/** |
2 | | - * @fileoverview Configures Webpack plugins. |
3 | | - */ |
4 | | - |
5 | 1 | import { resolve, dirname } from 'path'; |
6 | 2 | import webpack from 'webpack'; |
7 | 3 | import { CleanWebpackPlugin } from 'clean-webpack-plugin'; |
8 | | -import _MiniCssExtractPlugin from 'mini-css-extract-plugin'; |
9 | | -import _SpriteLoaderPlugin from 'svg-sprite-loader/plugin.js'; |
| 4 | +import MiniCssExtractPlugin from 'mini-css-extract-plugin'; |
| 5 | +import SpriteLoaderPlugin from 'svg-sprite-loader/plugin.js'; |
10 | 6 | import CopyPlugin from 'copy-webpack-plugin'; |
11 | 7 | import { sync as globSync } from 'glob'; |
12 | 8 | import fs from 'fs-extra'; |
13 | 9 | import emulsifyConfig from '../../../../../project.emulsify.json' with { type: 'json' }; |
14 | 10 |
|
15 | | -// Create __filename from import.meta.url without fileURLToPath |
16 | | -let _filename = decodeURIComponent(new URL(import.meta.url).pathname); |
17 | | - |
18 | | -// On Windows, remove the leading slash (e.g. "/C:/path" -> "C:/path") |
19 | | -if (process.platform === 'win32' && _filename.startsWith('/')) { |
20 | | - _filename = _filename.slice(1); |
| 11 | +/** |
| 12 | + * Resolve the directory of this file (without fileURLToPath). |
| 13 | + * @type {string} |
| 14 | + */ |
| 15 | +let __filename = decodeURIComponent(new URL(import.meta.url).pathname); |
| 16 | +if (process.platform === 'win32' && __filename.startsWith('/')) { |
| 17 | + __filename = __filename.slice(1); |
21 | 18 | } |
| 19 | +const __dirname = dirname(__filename); |
22 | 20 |
|
23 | | -const _dirname = dirname(_filename); |
24 | | - |
25 | | -const projectDir = resolve(_dirname, '../../../../..'); |
26 | | -const srcDir = resolve(projectDir, 'src'); |
27 | | - |
28 | | -const MiniCssExtractPlugin = new _MiniCssExtractPlugin({ |
29 | | - filename: '[name].css', |
30 | | - chunkFilename: '[id].css', |
31 | | -}); |
| 21 | +/** |
| 22 | + * Root of the project (three levels up from this file). |
| 23 | + * @type {string} |
| 24 | + */ |
| 25 | +const projectDir = resolve(__dirname, '../../../../..'); |
32 | 26 |
|
33 | | -const SpriteLoaderPlugin = new _SpriteLoaderPlugin({ |
34 | | - plainSprite: true, |
35 | | -}); |
| 27 | +/** |
| 28 | + * Where your source files live (if you have a `/src` folder). |
| 29 | + * Falls back to `components/` if `src/` does not exist. |
| 30 | + * @type {string} |
| 31 | + */ |
| 32 | +const srcPath = resolve(projectDir, 'src'); |
| 33 | +const isSrcExists = fs.pathExistsSync(srcPath); |
| 34 | +const srcDir = isSrcExists ? srcPath : resolve(projectDir, 'components'); |
36 | 35 |
|
37 | | -const ProgressPlugin = new webpack.ProgressPlugin(); |
| 36 | +/** |
| 37 | + * Where your built assets should live. |
| 38 | + * Mirrors the `srcDir` logic: prefer `dist/` if you have `src/`, else `components/`. |
| 39 | + * @type {string} |
| 40 | + */ |
| 41 | +const distPath = isSrcExists |
| 42 | + ? resolve(projectDir, 'dist') |
| 43 | + : resolve(projectDir, 'components'); |
38 | 44 |
|
| 45 | +/** |
| 46 | + * Glob pattern for all Twig & component files in your source. |
| 47 | + * We copy these through CopyPlugin so your PHP/Drupal theme sees them. |
| 48 | + * @type {string} |
| 49 | + */ |
39 | 50 | const componentFilesPattern = resolve( |
40 | 51 | srcDir, |
41 | 52 | '**/*.{twig,component.yml,component.json}', |
42 | 53 | ); |
43 | 54 |
|
44 | 55 | /** |
45 | | - * Prepare a list of patterns for copying Twig and component files. |
| 56 | + * Turn a globbed source list into copy patterns. |
46 | 57 | * |
47 | | - * @param {string} filesMatcher - Glob pattern for matching files. |
48 | | - * @returns {Array<Object>} Array of objects with `from` and `to` properties. |
| 58 | + * @param {string} filesMatcher Glob pattern. |
| 59 | + * @returns {Array<{from:string,to:string}>} |
49 | 60 | */ |
50 | 61 | function getPatterns(filesMatcher) { |
51 | | - const patterns = []; |
52 | | - globSync(filesMatcher).forEach((file) => { |
| 62 | + return globSync(filesMatcher).map((file) => { |
53 | 63 | const projectPath = file.split('/src/')[0]; |
54 | 64 | const srcStructure = file.split(`${srcDir}/`)[1]; |
55 | 65 | const parentDir = srcStructure.split('/')[0]; |
56 | | - const filePath = file.split(/(foundation\/|components\/|layout\/)/)[2]; |
| 66 | + // Consolidate foundation/layout under components for Drupal. |
57 | 67 | const consolidateDirs = |
58 | 68 | parentDir === 'layout' || parentDir === 'foundation' |
59 | 69 | ? '/components/' |
60 | 70 | : '/'; |
61 | | - const newfilePath = |
| 71 | + const filePath = file.split(/(foundation\/|components\/|layout\/)/)[2]; |
| 72 | + const destDir = |
62 | 73 | emulsifyConfig.project.platform === 'drupal' |
63 | 74 | ? `${projectPath}${consolidateDirs}${parentDir}/${filePath}` |
64 | 75 | : `${projectPath}/dist/${parentDir}/${filePath}`; |
65 | | - patterns.push({ |
66 | | - from: file, |
67 | | - to: newfilePath, |
68 | | - }); |
| 76 | + return { from: file, to: destDir }; |
69 | 77 | }); |
70 | | - return patterns; |
71 | 78 | } |
72 | 79 |
|
73 | | -const CopyTwigPlugin = fs.pathExistsSync(resolve(projectDir, 'src')) |
| 80 | +/** |
| 81 | + * Only include CopyPlugin if we actually have a `src/` folder. |
| 82 | + * @type {CopyPlugin|false} |
| 83 | + */ |
| 84 | +const CopyTwigPlugin = isSrcExists |
74 | 85 | ? new CopyPlugin({ patterns: getPatterns(componentFilesPattern) }) |
75 | | - : ''; |
| 86 | + : false; |
| 87 | + |
| 88 | +/** |
| 89 | + * CleanWebpackPlugin configuration. |
| 90 | + * Wipes out everything in `distPath` before a build, |
| 91 | + * except image files (we whitelist common image extensions). |
| 92 | + */ |
| 93 | +const CleanPlugin = new CleanWebpackPlugin({ |
| 94 | + protectWebpackAssets: false, |
| 95 | + cleanOnceBeforeBuildPatterns: [ |
| 96 | + // wipe all compiled assets |
| 97 | + `${distPath}/**/*`, |
| 98 | + // but keep any images |
| 99 | + `!${distPath}/**/*.png`, |
| 100 | + `!${distPath}/**/*.jpg`, |
| 101 | + `!${distPath}/**/*.gif`, |
| 102 | + `!${distPath}/**/*.svg`, |
| 103 | + ], |
| 104 | +}); |
| 105 | + |
| 106 | +/** |
| 107 | + * MiniCssExtractPlugin instance: writes `[name].css` into your dist. |
| 108 | + */ |
| 109 | +const CssExtractPlugin = new MiniCssExtractPlugin({ |
| 110 | + filename: '[name].css', |
| 111 | + chunkFilename: '[id].css', |
| 112 | +}); |
76 | 113 |
|
77 | | -const pluginConfig = { |
| 114 | +/** |
| 115 | + * svg-sprite-loader plugin: bundles all /icons/*.svg. |
| 116 | + */ |
| 117 | +const SpritePlugin = new SpriteLoaderPlugin({ |
| 118 | + plainSprite: true, |
| 119 | +}); |
| 120 | + |
| 121 | +/** |
| 122 | + * webpack.ProgressPlugin for nice build progress output. |
| 123 | + */ |
| 124 | +const ProgressPlugin = new webpack.ProgressPlugin(); |
| 125 | + |
| 126 | +/** |
| 127 | + * Export all plugins keyed for easy inclusion in your final Webpack config. |
| 128 | + */ |
| 129 | +export default { |
78 | 130 | ProgressPlugin, |
79 | | - MiniCssExtractPlugin, |
80 | | - SpriteLoaderPlugin, |
| 131 | + CleanWebpackPlugin: CleanPlugin, |
| 132 | + MiniCssExtractPlugin: CssExtractPlugin, |
| 133 | + SpriteLoaderPlugin: SpritePlugin, |
81 | 134 | CopyTwigPlugin, |
82 | | - CleanWebpackPlugin: new CleanWebpackPlugin({ |
83 | | - protectWebpackAssets: false, |
84 | | - cleanOnceBeforeBuildPatterns: ['!*.{png,jpg,gif,svg}'], |
85 | | - cleanAfterEveryBuildPatterns: [ |
86 | | - 'remove/**', |
87 | | - '!js', |
88 | | - 'css/**/*.js', |
89 | | - 'css/**/*.js.map', |
90 | | - '!*.{png,jpg,gif,svg}', |
91 | | - ], |
92 | | - }), |
93 | 135 | }; |
94 | | - |
95 | | -export default pluginConfig; |
|
0 commit comments