0
# Asset Management
1
2
@nx/js provides comprehensive static asset handling capabilities for copying, processing, and managing non-code files during the build process with support for glob patterns, watch mode, and flexible output configuration.
3
4
## Capabilities
5
6
### Asset Copying
7
8
High-performance asset copying with glob pattern support, filtering, and flexible input/output mapping.
9
10
```typescript { .api }
11
/**
12
* Copies static assets from source to destination with glob pattern support
13
* @param options - Asset copying configuration options
14
* @param context - Nx executor context for project information
15
* @returns Promise resolving to copy result with success status and optional cleanup
16
*/
17
function copyAssets(
18
options: CopyAssetsOptions,
19
context: ExecutorContext
20
): Promise<CopyAssetsResult>;
21
22
interface CopyAssetsOptions {
23
assets: Array<AssetGlob | string>; // Asset patterns or simple paths
24
outputPath: string; // Base output directory
25
watchMode?: WatchMode; // Optional watch mode configuration
26
}
27
28
interface CopyAssetsResult {
29
success: boolean; // Whether copy operation succeeded
30
stop?(): void; // Optional cleanup function for watch mode
31
}
32
33
interface WatchMode {
34
onCopy?: (files: string[]) => void; // Callback for when files are copied
35
}
36
```
37
38
**Usage Examples:**
39
40
```typescript
41
import { copyAssets } from "@nx/js";
42
43
// Basic asset copying
44
const result = await copyAssets({
45
assets: [
46
'src/assets/**/*', // Simple glob pattern
47
'README.md', // Single file
48
{
49
input: 'src/docs', // Source directory
50
output: './documentation', // Destination directory
51
glob: '**/*.md' // File pattern
52
}
53
],
54
outputPath: 'dist/my-app'
55
}, context);
56
57
// With watch mode
58
const watchResult = await copyAssets({
59
assets: ['src/assets/**/*'],
60
outputPath: 'dist/my-app',
61
watchMode: {
62
onCopy: (files) => {
63
console.log(`Copied ${files.length} files`);
64
}
65
}
66
}, context);
67
68
// Cleanup watcher when done
69
if (watchResult.stop) {
70
watchResult.stop();
71
}
72
```
73
74
### Asset Glob Processing
75
76
Converts asset glob patterns and configurations into concrete file input/output mappings.
77
78
```typescript { .api }
79
/**
80
* Converts asset globs to concrete file input/output mappings
81
* @param assets - Array of asset patterns or configurations
82
* @param rootDir - Root directory for resolving relative paths
83
* @param outDir - Base output directory for assets
84
* @returns Array of file input/output mappings
85
*/
86
function assetGlobsToFiles(
87
assets: Array<AssetGlob | string>,
88
rootDir: string,
89
outDir: string
90
): FileInputOutput[];
91
92
interface FileInputOutput {
93
input: string; // Source file path
94
output: string; // Destination file path
95
}
96
97
interface AssetGlob extends FileInputOutput {
98
glob: string; // Glob pattern for matching files
99
ignore?: string[]; // Patterns to ignore
100
dot?: boolean; // Include dotfiles (default: false)
101
includeIgnoredFiles?: boolean; // Include files ignored by .gitignore
102
}
103
```
104
105
**Usage Examples:**
106
107
```typescript
108
import { assetGlobsToFiles } from "@nx/js";
109
110
// Convert asset configurations to file mappings
111
const fileMap = assetGlobsToFiles([
112
'src/assets/**/*', // Simple pattern
113
{
114
input: 'src/images', // Source directory
115
output: './assets/images', // Output directory
116
glob: '**/*.{png,jpg,gif}', // Image files only
117
ignore: ['**/*.tmp'], // Ignore temporary files
118
dot: false // Exclude dotfiles
119
},
120
{
121
input: 'docs',
122
output: './documentation',
123
glob: '**/*.md',
124
includeIgnoredFiles: true // Include gitignored files
125
}
126
], 'libs/my-lib', 'dist/libs/my-lib');
127
128
// Results in array like:
129
// [
130
// { input: 'libs/my-lib/src/assets/logo.png', output: 'dist/libs/my-lib/logo.png' },
131
// { input: 'libs/my-lib/src/images/hero.jpg', output: 'dist/libs/my-lib/assets/images/hero.jpg' },
132
// { input: 'libs/my-lib/docs/README.md', output: 'dist/libs/my-lib/documentation/README.md' }
133
// ]
134
```
135
136
## Asset Configuration Types
137
138
### Simple String Patterns
139
140
Use simple glob strings for basic asset copying:
141
142
```typescript
143
const assets = [
144
'src/assets/**/*', // All files in assets directory
145
'*.md', // All markdown files in root
146
'public/**/*.{html,css,js}' // Web assets
147
];
148
```
149
150
### Advanced Asset Globs
151
152
Use AssetGlob objects for precise control over asset handling:
153
154
```typescript
155
const assets: AssetGlob[] = [
156
{
157
input: 'src/assets', // Source directory
158
output: './static', // Output subdirectory
159
glob: '**/*', // All files recursively
160
ignore: ['**/*.tmp', '**/.DS_Store'], // Ignore patterns
161
dot: false, // Exclude dotfiles
162
includeIgnoredFiles: false // Respect .gitignore
163
},
164
{
165
input: 'src/translations',
166
output: './i18n',
167
glob: '*.json', // JSON files only
168
dot: true, // Include dotfiles
169
includeIgnoredFiles: true // Include ignored files
170
}
171
];
172
```
173
174
### Mixed Asset Configurations
175
176
Combine simple strings and detailed configurations:
177
178
```typescript
179
const assets = [
180
'README.md', // Simple file copy
181
'LICENSE', // Another simple file
182
{
183
input: 'src/assets', // Detailed configuration
184
output: './assets',
185
glob: '**/*.{png,jpg,svg}',
186
ignore: ['**/*-temp.*']
187
},
188
'src/styles/**/*.css' // Simple glob pattern
189
];
190
```
191
192
## Asset Management Patterns
193
194
### Build-Time Asset Processing
195
196
Copy different assets based on build configuration:
197
198
```typescript
199
// Development assets (includes source maps, unminified files)
200
const devAssets = [
201
'src/assets/**/*',
202
'src/styles/**/*.css',
203
'src/scripts/**/*.js'
204
];
205
206
// Production assets (optimized, compressed)
207
const prodAssets = [
208
{
209
input: 'src/assets',
210
output: './assets',
211
glob: '**/*.{png,jpg,svg,webp}', // Image assets only
212
ignore: ['**/*-dev.*'] // Exclude development assets
213
},
214
{
215
input: 'dist/styles', // Pre-processed styles
216
output: './styles',
217
glob: '*.min.css' // Minified CSS only
218
}
219
];
220
```
221
222
### Conditional Asset Inclusion
223
224
Include different assets based on environment or configuration:
225
226
```typescript
227
const baseAssets = ['README.md', 'LICENSE'];
228
229
const environmentAssets = process.env.NODE_ENV === 'production'
230
? [
231
{
232
input: 'src/assets/prod',
233
output: './assets',
234
glob: '**/*'
235
}
236
]
237
: [
238
{
239
input: 'src/assets/dev',
240
output: './assets',
241
glob: '**/*',
242
includeIgnoredFiles: true
243
}
244
];
245
246
const allAssets = [...baseAssets, ...environmentAssets];
247
```
248
249
### Watch Mode Integration
250
251
Use asset copying with file watching for development:
252
253
```typescript
254
import { copyAssets } from "@nx/js";
255
256
const setupAssetWatcher = async () => {
257
const result = await copyAssets({
258
assets: ['src/assets/**/*'],
259
outputPath: 'dist/my-app',
260
watchMode: {
261
onCopy: (files) => {
262
console.log(`Asset update: ${files.length} files copied`);
263
// Trigger other processes like live reload
264
notifyLiveReload();
265
}
266
}
267
}, context);
268
269
// Return cleanup function
270
return () => {
271
if (result.stop) {
272
result.stop();
273
}
274
};
275
};
276
277
// Use in development server
278
const stopWatching = await setupAssetWatcher();
279
280
// Cleanup on exit
281
process.on('SIGINT', () => {
282
stopWatching();
283
process.exit(0);
284
});
285
```
286
287
### Asset Organization Strategies
288
289
Organize assets by type, environment, or feature:
290
291
```typescript
292
// By asset type
293
const assetsByType = [
294
{
295
input: 'src/images',
296
output: './assets/images',
297
glob: '**/*.{png,jpg,jpeg,gif,svg,webp}',
298
ignore: ['**/*-temp.*']
299
},
300
{
301
input: 'src/fonts',
302
output: './assets/fonts',
303
glob: '**/*.{woff,woff2,ttf,eot}',
304
dot: false
305
},
306
{
307
input: 'src/data',
308
output: './assets/data',
309
glob: '**/*.{json,csv,xml}',
310
includeIgnoredFiles: false
311
}
312
];
313
314
// By feature or module
315
const assetsByFeature = [
316
{
317
input: 'src/modules/dashboard/assets',
318
output: './assets/dashboard',
319
glob: '**/*'
320
},
321
{
322
input: 'src/modules/profile/assets',
323
output: './assets/profile',
324
glob: '**/*'
325
}
326
];
327
```
328
329
### Integration with Build Tools
330
331
Combine asset copying with other build processes:
332
333
```typescript
334
// In an executor or build script
335
const buildWithAssets = async (options, context) => {
336
// 1. Clean output directory
337
await fs.remove(options.outputPath);
338
339
// 2. Compile TypeScript/JavaScript
340
await compileCode(options, context);
341
342
// 3. Copy assets
343
const assetResult = await copyAssets({
344
assets: options.assets,
345
outputPath: options.outputPath
346
}, context);
347
348
// 4. Generate package.json
349
if (options.generatePackageJson) {
350
await generatePackageJson(options, context);
351
}
352
353
return {
354
success: assetResult.success
355
};
356
};
357
```
358
359
## Error Handling
360
361
Asset operations include comprehensive error handling:
362
363
```typescript
364
try {
365
const result = await copyAssets({
366
assets: ['src/assets/**/*'],
367
outputPath: 'dist/my-app'
368
}, context);
369
370
if (!result.success) {
371
console.error('Asset copying failed');
372
process.exit(1);
373
}
374
} catch (error) {
375
console.error('Asset copying error:', error.message);
376
// Handle specific error types
377
if (error.code === 'ENOENT') {
378
console.error('Source asset directory not found');
379
}
380
process.exit(1);
381
}
382
```