1- import { resolve , dirname } from 'path' ;
1+ import { resolve , dirname , relative } from 'path' ;
22import webpack from 'webpack' ;
33import { CleanWebpackPlugin } from 'clean-webpack-plugin' ;
44import RemoveEmptyScriptsPlugin from 'webpack-remove-empty-scripts' ;
@@ -61,7 +61,7 @@ const componentsSrcRoot = isSrcExists ? resolve(srcDir, 'components') : srcDir;
6161 * Component output root (where compiled component assets go):
6262 * - Drupal + src/: `components/…`
6363 * - Otherwise: `dist/components/…`
64- * (Relative to `projectDir`; used by CopyPlugin’s `to:` path.)
64+ * (Relative to `projectDir`; used by CopyPlugins `to:` path.)
6565 * @type {string }
6666 */
6767const componentsOutRoot =
@@ -94,7 +94,9 @@ function getPatterns(filesMatcher) {
9494 parentDir === 'layout' || parentDir === 'foundation'
9595 ? '/components/'
9696 : '/' ;
97+
9798 const filePath = file . split ( / ( f o u n d a t i o n \/ | c o m p o n e n t s \/ | l a y o u t \/ ) / ) [ 2 ] ;
99+
98100 const to = isDrupal
99101 ? `${ projectPath } ${ consolidateDirs } ${ parentDir } /${ filePath } `
100102 : `${ projectPath } /dist/${ parentDir } /${ filePath } ` ;
@@ -112,63 +114,113 @@ const CopyTwigPlugin = isSrcExists
112114 ? new CopyPlugin ( { patterns : getPatterns ( componentFilesPattern ) } )
113115 : false ;
114116
117+ /* -------------------------------------------------------------------------- */
118+ /* COMPONENT & GLOBAL ASSETS */
119+ /* -------------------------------------------------------------------------- */
120+
121+ /**
122+ * Asset allow-list (extensions we consider "static assets" to mirror).
123+ * Extend to suit your project (e.g., add `pdf`, `txt`, `xml`, etc.).
124+ * NOTE: We purposefully exclude code-like files via the filter below.
125+ * @type {RegExp }
126+ */
127+ const ASSET_EXT_RE =
128+ / \. (?: p n g | j p e ? g | g i f | s v g | w e b p | a v i f | i c o | b m p | h e i c | h e i f | m p 4 | w e b m | m p 3 | o g g | w a v | a a c | w o f f 2 ? | t t f | o t f | e o t | j s o n | w e b m a n i f e s t | m a n i f e s t | p d f ) $ / i;
129+
130+ /**
131+ * Exclude code & tooling files (don’t mirror these).
132+ * @type {RegExp }
133+ */
134+ const EXCLUDE_CODE_RE =
135+ / \. (?: j s x ? | t s x ? | m j s | c j s | v u e | s v e l t e | s c s s | s a s s | l e s s | s t y l | c s s | m a p | t w i g | p h p | y m l | y a m l | m d | m a r k d o w n | s t o r y (?: b o o k ) ? \. [ j t ] s x ? | s t o r i e s \. [ j t ] s x ? | t e s t \. [ j t ] s x ? ) $ / i;
136+
115137/**
116- * CopyPlugin instance: copies **component-local assets** (images, fonts, SVGs, etc.)
138+ * Shared filter for CopyPlugin patterns.
139+ * Decides whether a file should be copied as a "static asset".
117140 *
118- * Example:
141+ * @param {string } resourcePath - Absolute file path on disk.
142+ * @param {string } base - The context directory for the pattern.
143+ * @returns {boolean } True if we should copy the file.
144+ */
145+ const assetFilter = ( resourcePath , base ) => {
146+ const rel = relative ( base , resourcePath ) ;
147+ // Guard: stay inside context
148+ if ( rel . startsWith ( '..' ) ) return false ;
149+ // Exclude typical code/tooling files
150+ if ( EXCLUDE_CODE_RE . test ( rel ) ) return false ;
151+ // Include known asset extensions
152+ return ASSET_EXT_RE . test ( rel ) ;
153+ } ;
154+
155+ /**
156+ * Copy **all static assets inside components**, regardless of folder labels.
157+ *
158+ * Examples (all preserved under the component’s output root):
119159 * src/components/accordion/assets/dropdown-icon.svg
120- * -> (Drupal+src) components/accordion/assets/dropdown-icon .svg
121- * -> (WP/legacy) dist /components/accordion/assets/dropdown- icon.svg
160+ * src/ components/accordion/images/icons/chevron .svg
161+ * src /components/accordion/icon.svg (root-level asset)
122162 *
123- * Notes:
124- * - `context` is set to the component source root so `[path]` starts **after**
125- * `…/components/`.
126- * - `to` uses `[path][name][ext]` to mirror the original tree.
127- * - `noErrorOnMissing` avoids errors if no assets are present.
128163 * @type {CopyPlugin }
129164 */
130165const CopyComponentAssetsPlugin = new CopyPlugin ( {
131166 patterns : [
132167 {
133- from : '**/assets/**/*' ,
168+ // Start at the components root and evaluate every file
169+ from : '**/*' ,
134170 context : componentsSrcRoot ,
135171 to : resolve ( projectDir , componentsOutRoot , '[path][name][ext]' ) ,
136172 noErrorOnMissing : true ,
137173 globOptions : {
138174 dot : false ,
139- ignore : [ '**/.DS_Store' , '**/Thumbs.db' ] ,
175+ ignore : [
176+ '**/.DS_Store' ,
177+ '**/Thumbs.db' ,
178+ '**/node_modules/**' ,
179+ '**/dist/**' ,
180+ ] ,
140181 } ,
182+ // Only copy files that match our asset allow-list and are not code
183+ filter : ( resourcePath ) => assetFilter ( resourcePath , componentsSrcRoot ) ,
141184 } ,
142185 ] ,
143186} ) ;
144187
145188/**
146- * CopyPlugin instance for **global (non-component) assets** that live
147- * under `src/` but *outside* `src/components/`.
148- *
149- * These are mirrored under `dist/global/…` (because your base SCSS/JS already
150- * use the `dist/global` convention).
189+ * OPTIONAL: Copy **global (non-component) assets** that live under `src/`
190+ * but outside `src/components/` (e.g. layout/site assets).
151191 *
192+ * Mirrors them under `dist/global/…`.
152193 * Disabled when there is no `src/` directory.
194+ *
153195 * @type {CopyPlugin|false }
154196 */
155197const CopyGlobalAssetsPlugin = isSrcExists
156198 ? new CopyPlugin ( {
157199 patterns : [
158200 {
159- from : '!(components|util)/**/assets/**/ *' ,
201+ from : '!(components|util)/**/*' ,
160202 context : srcDir ,
161203 to : resolve ( projectDir , 'dist' , 'global' , '[path][name][ext]' ) ,
162204 noErrorOnMissing : true ,
163205 globOptions : {
164206 dot : false ,
165- ignore : [ '**/.DS_Store' , '**/Thumbs.db' ] ,
207+ ignore : [
208+ '**/.DS_Store' ,
209+ '**/Thumbs.db' ,
210+ '**/node_modules/**' ,
211+ '**/dist/**' ,
212+ ] ,
166213 } ,
214+ filter : ( resourcePath ) => assetFilter ( resourcePath , srcDir ) ,
167215 } ,
168216 ] ,
169217 } )
170218 : false ;
171219
220+ /* -------------------------------------------------------------------------- */
221+ /* OTHER PLUGINS */
222+ /* -------------------------------------------------------------------------- */
223+
172224/**
173225 * CleanWebpackPlugin configuration.
174226 * Wipes out compiled CSS/JS in `distPath` before a build; keeps images.
0 commit comments