CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-nx--js

The JS plugin for Nx contains executors and generators that provide the best experience for developing JavaScript and TypeScript projects.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

asset-management.mddocs/

Asset Management

@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.

Capabilities

Asset Copying

High-performance asset copying with glob pattern support, filtering, and flexible input/output mapping.

/**
 * Copies static assets from source to destination with glob pattern support
 * @param options - Asset copying configuration options
 * @param context - Nx executor context for project information
 * @returns Promise resolving to copy result with success status and optional cleanup
 */
function copyAssets(
  options: CopyAssetsOptions,
  context: ExecutorContext
): Promise<CopyAssetsResult>;

interface CopyAssetsOptions {
  assets: Array<AssetGlob | string>;    // Asset patterns or simple paths
  outputPath: string;                   // Base output directory
  watchMode?: WatchMode;                // Optional watch mode configuration
}

interface CopyAssetsResult {
  success: boolean;                     // Whether copy operation succeeded
  stop?(): void;                        // Optional cleanup function for watch mode
}

interface WatchMode {
  onCopy?: (files: string[]) => void;   // Callback for when files are copied
}

Usage Examples:

import { copyAssets } from "@nx/js";

// Basic asset copying
const result = await copyAssets({
  assets: [
    'src/assets/**/*',                  // Simple glob pattern
    'README.md',                        // Single file
    {
      input: 'src/docs',                // Source directory
      output: './documentation',        // Destination directory
      glob: '**/*.md'                   // File pattern
    }
  ],
  outputPath: 'dist/my-app'
}, context);

// With watch mode
const watchResult = await copyAssets({
  assets: ['src/assets/**/*'],
  outputPath: 'dist/my-app',
  watchMode: {
    onCopy: (files) => {
      console.log(`Copied ${files.length} files`);
    }
  }
}, context);

// Cleanup watcher when done
if (watchResult.stop) {
  watchResult.stop();
}

Asset Glob Processing

Converts asset glob patterns and configurations into concrete file input/output mappings.

/**
 * Converts asset globs to concrete file input/output mappings
 * @param assets - Array of asset patterns or configurations
 * @param rootDir - Root directory for resolving relative paths
 * @param outDir - Base output directory for assets
 * @returns Array of file input/output mappings
 */
function assetGlobsToFiles(
  assets: Array<AssetGlob | string>,
  rootDir: string,
  outDir: string
): FileInputOutput[];

interface FileInputOutput {
  input: string;                        // Source file path
  output: string;                       // Destination file path
}

interface AssetGlob extends FileInputOutput {
  glob: string;                         // Glob pattern for matching files
  ignore?: string[];                    // Patterns to ignore
  dot?: boolean;                        // Include dotfiles (default: false)
  includeIgnoredFiles?: boolean;        // Include files ignored by .gitignore
}

Usage Examples:

import { assetGlobsToFiles } from "@nx/js";

// Convert asset configurations to file mappings
const fileMap = assetGlobsToFiles([
  'src/assets/**/*',                    // Simple pattern
  {
    input: 'src/images',                // Source directory
    output: './assets/images',          // Output directory
    glob: '**/*.{png,jpg,gif}',         // Image files only
    ignore: ['**/*.tmp'],               // Ignore temporary files
    dot: false                          // Exclude dotfiles
  },
  {
    input: 'docs',
    output: './documentation',
    glob: '**/*.md',
    includeIgnoredFiles: true           // Include gitignored files
  }
], 'libs/my-lib', 'dist/libs/my-lib');

// Results in array like:
// [
//   { input: 'libs/my-lib/src/assets/logo.png', output: 'dist/libs/my-lib/logo.png' },
//   { input: 'libs/my-lib/src/images/hero.jpg', output: 'dist/libs/my-lib/assets/images/hero.jpg' },
//   { input: 'libs/my-lib/docs/README.md', output: 'dist/libs/my-lib/documentation/README.md' }
// ]

Asset Configuration Types

Simple String Patterns

Use simple glob strings for basic asset copying:

const assets = [
  'src/assets/**/*',                    // All files in assets directory
  '*.md',                               // All markdown files in root
  'public/**/*.{html,css,js}'           // Web assets
];

Advanced Asset Globs

Use AssetGlob objects for precise control over asset handling:

const assets: AssetGlob[] = [
  {
    input: 'src/assets',                // Source directory
    output: './static',                 // Output subdirectory
    glob: '**/*',                       // All files recursively
    ignore: ['**/*.tmp', '**/.DS_Store'], // Ignore patterns
    dot: false,                         // Exclude dotfiles
    includeIgnoredFiles: false          // Respect .gitignore
  },
  {
    input: 'src/translations',
    output: './i18n',
    glob: '*.json',                     // JSON files only
    dot: true,                          // Include dotfiles
    includeIgnoredFiles: true           // Include ignored files
  }
];

Mixed Asset Configurations

Combine simple strings and detailed configurations:

const assets = [
  'README.md',                          // Simple file copy
  'LICENSE',                            // Another simple file
  {
    input: 'src/assets',                // Detailed configuration
    output: './assets',
    glob: '**/*.{png,jpg,svg}',
    ignore: ['**/*-temp.*']
  },
  'src/styles/**/*.css'                 // Simple glob pattern
];

Asset Management Patterns

Build-Time Asset Processing

Copy different assets based on build configuration:

// Development assets (includes source maps, unminified files)
const devAssets = [
  'src/assets/**/*',
  'src/styles/**/*.css',
  'src/scripts/**/*.js'
];

// Production assets (optimized, compressed)
const prodAssets = [
  {
    input: 'src/assets',
    output: './assets',
    glob: '**/*.{png,jpg,svg,webp}',    // Image assets only
    ignore: ['**/*-dev.*']              // Exclude development assets
  },
  {
    input: 'dist/styles',               // Pre-processed styles
    output: './styles',
    glob: '*.min.css'                   // Minified CSS only
  }
];

Conditional Asset Inclusion

Include different assets based on environment or configuration:

const baseAssets = ['README.md', 'LICENSE'];

const environmentAssets = process.env.NODE_ENV === 'production'
  ? [
      {
        input: 'src/assets/prod',
        output: './assets',
        glob: '**/*'
      }
    ]
  : [
      {
        input: 'src/assets/dev',
        output: './assets',
        glob: '**/*',
        includeIgnoredFiles: true
      }
    ];

const allAssets = [...baseAssets, ...environmentAssets];

Watch Mode Integration

Use asset copying with file watching for development:

import { copyAssets } from "@nx/js";

const setupAssetWatcher = async () => {
  const result = await copyAssets({
    assets: ['src/assets/**/*'],
    outputPath: 'dist/my-app',
    watchMode: {
      onCopy: (files) => {
        console.log(`Asset update: ${files.length} files copied`);
        // Trigger other processes like live reload
        notifyLiveReload();
      }
    }
  }, context);

  // Return cleanup function
  return () => {
    if (result.stop) {
      result.stop();
    }
  };
};

// Use in development server
const stopWatching = await setupAssetWatcher();

// Cleanup on exit
process.on('SIGINT', () => {
  stopWatching();
  process.exit(0);
});

Asset Organization Strategies

Organize assets by type, environment, or feature:

// By asset type
const assetsByType = [
  {
    input: 'src/images',
    output: './assets/images',
    glob: '**/*.{png,jpg,jpeg,gif,svg,webp}',
    ignore: ['**/*-temp.*']
  },
  {
    input: 'src/fonts',
    output: './assets/fonts',
    glob: '**/*.{woff,woff2,ttf,eot}',
    dot: false
  },
  {
    input: 'src/data',
    output: './assets/data',
    glob: '**/*.{json,csv,xml}',
    includeIgnoredFiles: false
  }
];

// By feature or module
const assetsByFeature = [
  {
    input: 'src/modules/dashboard/assets',
    output: './assets/dashboard',
    glob: '**/*'
  },
  {
    input: 'src/modules/profile/assets',
    output: './assets/profile',
    glob: '**/*'
  }
];

Integration with Build Tools

Combine asset copying with other build processes:

// In an executor or build script
const buildWithAssets = async (options, context) => {
  // 1. Clean output directory
  await fs.remove(options.outputPath);

  // 2. Compile TypeScript/JavaScript
  await compileCode(options, context);

  // 3. Copy assets
  const assetResult = await copyAssets({
    assets: options.assets,
    outputPath: options.outputPath
  }, context);

  // 4. Generate package.json
  if (options.generatePackageJson) {
    await generatePackageJson(options, context);
  }

  return {
    success: assetResult.success
  };
};

Error Handling

Asset operations include comprehensive error handling:

try {
  const result = await copyAssets({
    assets: ['src/assets/**/*'],
    outputPath: 'dist/my-app'
  }, context);

  if (!result.success) {
    console.error('Asset copying failed');
    process.exit(1);
  }
} catch (error) {
  console.error('Asset copying error:', error.message);
  // Handle specific error types
  if (error.code === 'ENOENT') {
    console.error('Source asset directory not found');
  }
  process.exit(1);
}

Install with Tessl CLI

npx tessl i tessl/npm-nx--js

docs

additional-utilities.md

asset-management.md

executors.md

generators.md

index.md

package-management.md

typescript-utilities.md

tile.json