import * as CopyWebpackPlugin from 'copy-webpack-plugin'; import { normalizePath } from 'nx/src/utils/path'; import { basename, dirname, join, relative, resolve } from 'path'; import { statSync } from 'fs'; interface AssetGlobPattern { glob: string; input: string; output: string; ignore?: string[]; } function normalizeAssets( assets: any[], root: string, sourceRoot: string ): AssetGlobPattern[] { return assets.map((asset) => { if (typeof asset === 'string') { const assetPath = normalizePath(asset); const resolvedAssetPath = resolve(root, assetPath); const resolvedSourceRoot = resolve(root, sourceRoot); if (!resolvedAssetPath.startsWith(resolvedSourceRoot)) { throw new Error( `The ${resolvedAssetPath} asset path must start with the project source root: ${sourceRoot}` ); } const isDirectory = statSync(resolvedAssetPath).isDirectory(); const input = isDirectory ? resolvedAssetPath : dirname(resolvedAssetPath); const output = relative(resolvedSourceRoot, resolve(root, input)); const glob = isDirectory ? '**/*' : basename(resolvedAssetPath); return { input, output, glob, }; } else { if (asset.output.startsWith('..')) { throw new Error( 'An asset cannot be written to a location outside of the output path.' ); } const assetPath = normalizePath(asset.input); const resolvedAssetPath = resolve(root, assetPath); return { ...asset, input: resolvedAssetPath, // Now we remove starting slash to make Webpack place it from the output root. output: asset.output.replace(/^\//, ''), }; } }); } export function createCopyPlugin( assets: any[], root: string, sourceRoot: string ) { return new CopyWebpackPlugin({ patterns: normalizeAssets(assets, root, sourceRoot).map((asset) => { return { context: asset.input, to: join('../public', asset.output), from: asset.glob, globOptions: { ignore: [ '.gitkeep', '**/.DS_Store', '**/Thumbs.db', ...(asset.ignore ?? []), ], dot: true, }, }; }), }); }