123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822 |
- "use strict";
- const path = require("path");
- const {
- validate
- } = require("schema-utils");
- // @ts-ignore
- const {
- version
- } = require("../package.json");
- const schema = require("./options.json");
- const {
- readFile,
- stat,
- throttleAll,
- memoize
- } = require("./utils");
- const template = /\[\\*([\w:]+)\\*\]/i;
- const getNormalizePath = memoize(() =>
- // eslint-disable-next-line global-require
- require("normalize-path"));
- const getGlobParent = memoize(() =>
- // eslint-disable-next-line global-require
- require("glob-parent"));
- const getSerializeJavascript = memoize(() =>
- // eslint-disable-next-line global-require
- require("serialize-javascript"));
- const getFastGlob = memoize(() =>
- // eslint-disable-next-line global-require
- require("fast-glob"));
- const getGlobby = memoize(async () => {
- // @ts-ignore
- const {
- globby
- } = await import("globby");
- return globby;
- });
- /** @typedef {import("schema-utils/declarations/validate").Schema} Schema */
- /** @typedef {import("webpack").Compiler} Compiler */
- /** @typedef {import("webpack").Compilation} Compilation */
- /** @typedef {import("webpack").WebpackError} WebpackError */
- /** @typedef {import("webpack").Asset} Asset */
- /** @typedef {import("globby").Options} GlobbyOptions */
- /** @typedef {import("globby").GlobEntry} GlobEntry */
- /** @typedef {ReturnType<Compilation["getLogger"]>} WebpackLogger */
- /** @typedef {ReturnType<Compilation["getCache"]>} CacheFacade */
- /** @typedef {ReturnType<ReturnType<Compilation["getCache"]>["getLazyHashedEtag"]>} Etag */
- /** @typedef {ReturnType<Compilation["fileSystemInfo"]["mergeSnapshots"]>} Snapshot */
- /**
- * @typedef {boolean} Force
- */
- /**
- * @typedef {Object} CopiedResult
- * @property {string} sourceFilename
- * @property {string} absoluteFilename
- * @property {string} filename
- * @property {Asset["source"]} source
- * @property {Force | undefined} force
- * @property {Record<string, any>} info
- */
- /**
- * @typedef {string} StringPattern
- */
- /**
- * @typedef {boolean} NoErrorOnMissing
- */
- /**
- * @typedef {string} Context
- */
- /**
- * @typedef {string} From
- */
- /**
- * @callback ToFunction
- * @param {{ context: string, absoluteFilename?: string }} pathData
- * @return {string | Promise<string>}
- */
- /**
- * @typedef {string | ToFunction} To
- */
- /**
- * @typedef {"dir" | "file" | "template"} ToType
- */
- /**
- * @callback TransformerFunction
- * @param {Buffer} input
- * @param {string} absoluteFilename
- * @returns {string | Buffer | Promise<string> | Promise<Buffer>}
- */
- /**
- * @typedef {{ keys: { [key: string]: any } } | { keys: ((defaultCacheKeys: { [key: string]: any }, absoluteFilename: string) => Promise<{ [key: string]: any }>) }} TransformerCacheObject
- */
- /**
- * @typedef {Object} TransformerObject
- * @property {TransformerFunction} transformer
- * @property {boolean | TransformerCacheObject} [cache]
- */
- /**
- * @typedef {TransformerFunction | TransformerObject} Transform
- */
- /**
- * @callback Filter
- * @param {string} filepath
- * @returns {boolean | Promise<boolean>}
- */
- /**
- * @callback TransformAllFunction
- * @param {{ data: Buffer, sourceFilename: string, absoluteFilename: string }[]} data
- * @returns {string | Buffer | Promise<string> | Promise<Buffer>}
- */
- /**
- * @typedef { Record<string, any> | ((item: { absoluteFilename: string, sourceFilename: string, filename: string, toType: ToType }) => Record<string, any>) } Info
- */
- /**
- * @typedef {Object} ObjectPattern
- * @property {From} from
- * @property {GlobbyOptions} [globOptions]
- * @property {Context} [context]
- * @property {To} [to]
- * @property {ToType} [toType]
- * @property {Info} [info]
- * @property {Filter} [filter]
- * @property {Transform} [transform]
- * @property {TransformAllFunction} [transformAll]
- * @property {Force} [force]
- * @property {number} [priority]
- * @property {NoErrorOnMissing} [noErrorOnMissing]
- */
- /**
- * @typedef {StringPattern | ObjectPattern} Pattern
- */
- /**
- * @typedef {Object} AdditionalOptions
- * @property {number} [concurrency]
- */
- /**
- * @typedef {Object} PluginOptions
- * @property {Pattern[]} patterns
- * @property {AdditionalOptions} [options]
- */
- class CopyPlugin {
- /**
- * @param {PluginOptions} [options]
- */
- constructor(options = {
- patterns: []
- }) {
- validate( /** @type {Schema} */schema, options, {
- name: "Copy Plugin",
- baseDataPath: "options"
- });
- /**
- * @private
- * @type {Pattern[]}
- */
- this.patterns = options.patterns;
- /**
- * @private
- * @type {AdditionalOptions}
- */
- this.options = options.options || {};
- }
- /**
- * @private
- * @param {Compilation} compilation
- * @param {number} startTime
- * @param {string} dependency
- * @returns {Promise<Snapshot | undefined>}
- */
- static async createSnapshot(compilation, startTime, dependency) {
- // eslint-disable-next-line consistent-return
- return new Promise((resolve, reject) => {
- compilation.fileSystemInfo.createSnapshot(startTime, [dependency],
- // @ts-ignore
- // eslint-disable-next-line no-undefined
- undefined,
- // eslint-disable-next-line no-undefined
- undefined, null, (error, snapshot) => {
- if (error) {
- reject(error);
- return;
- }
- resolve( /** @type {Snapshot} */snapshot);
- });
- });
- }
- /**
- * @private
- * @param {Compilation} compilation
- * @param {Snapshot} snapshot
- * @returns {Promise<boolean | undefined>}
- */
- static async checkSnapshotValid(compilation, snapshot) {
- // eslint-disable-next-line consistent-return
- return new Promise((resolve, reject) => {
- compilation.fileSystemInfo.checkSnapshotValid(snapshot, (error, isValid) => {
- if (error) {
- reject(error);
- return;
- }
- resolve(isValid);
- });
- });
- }
- /**
- * @private
- * @param {Compiler} compiler
- * @param {Compilation} compilation
- * @param {Buffer} source
- * @returns {string}
- */
- static getContentHash(compiler, compilation, source) {
- const {
- outputOptions
- } = compilation;
- const {
- hashDigest,
- hashDigestLength,
- hashFunction,
- hashSalt
- } = outputOptions;
- const hash = compiler.webpack.util.createHash( /** @type {string} */hashFunction);
- if (hashSalt) {
- hash.update(hashSalt);
- }
- hash.update(source);
- const fullContentHash = hash.digest(hashDigest);
- return fullContentHash.toString().slice(0, hashDigestLength);
- }
- /**
- * @private
- * @param {typeof import("globby").globby} globby
- * @param {Compiler} compiler
- * @param {Compilation} compilation
- * @param {WebpackLogger} logger
- * @param {CacheFacade} cache
- * @param {ObjectPattern & { context: string }} inputPattern
- * @param {number} index
- * @returns {Promise<Array<CopiedResult | undefined> | undefined>}
- */
- static async runPattern(globby, compiler, compilation, logger, cache, inputPattern, index) {
- const {
- RawSource
- } = compiler.webpack.sources;
- const pattern = {
- ...inputPattern
- };
- const originalFrom = pattern.from;
- const normalizedOriginalFrom = path.normalize(originalFrom);
- logger.log(`starting to process a pattern from '${normalizedOriginalFrom}' using '${pattern.context}' context`);
- let absoluteFrom;
- if (path.isAbsolute(normalizedOriginalFrom)) {
- absoluteFrom = normalizedOriginalFrom;
- } else {
- absoluteFrom = path.resolve(pattern.context, normalizedOriginalFrom);
- }
- logger.debug(`getting stats for '${absoluteFrom}'...`);
- const {
- inputFileSystem
- } = compiler;
- let stats;
- try {
- stats = await stat(inputFileSystem, absoluteFrom);
- } catch (error) {
- // Nothing
- }
- /**
- * @type {"file" | "dir" | "glob"}
- */
- let fromType;
- if (stats) {
- if (stats.isDirectory()) {
- fromType = "dir";
- logger.debug(`determined '${absoluteFrom}' is a directory`);
- } else if (stats.isFile()) {
- fromType = "file";
- logger.debug(`determined '${absoluteFrom}' is a file`);
- } else {
- // Fallback
- fromType = "glob";
- logger.debug(`determined '${absoluteFrom}' is unknown`);
- }
- } else {
- fromType = "glob";
- logger.debug(`determined '${absoluteFrom}' is a glob`);
- }
- /** @type {GlobbyOptions & { objectMode: true }} */
- const globOptions = {
- ...{
- followSymbolicLinks: true
- },
- ...(pattern.globOptions || {}),
- ...{
- cwd: pattern.context,
- objectMode: true
- }
- };
- // @ts-ignore
- globOptions.fs = inputFileSystem;
- let glob;
- switch (fromType) {
- case "dir":
- compilation.contextDependencies.add(absoluteFrom);
- logger.debug(`added '${absoluteFrom}' as a context dependency`);
- pattern.context = absoluteFrom;
- glob = path.posix.join(getFastGlob().escapePath(getNormalizePath()(path.resolve(absoluteFrom))), "**/*");
- absoluteFrom = path.join(absoluteFrom, "**/*");
- if (typeof globOptions.dot === "undefined") {
- globOptions.dot = true;
- }
- break;
- case "file":
- compilation.fileDependencies.add(absoluteFrom);
- logger.debug(`added '${absoluteFrom}' as a file dependency`);
- pattern.context = path.dirname(absoluteFrom);
- glob = getFastGlob().escapePath(getNormalizePath()(path.resolve(absoluteFrom)));
- if (typeof globOptions.dot === "undefined") {
- globOptions.dot = true;
- }
- break;
- case "glob":
- default:
- {
- const contextDependencies = path.normalize(getGlobParent()(absoluteFrom));
- compilation.contextDependencies.add(contextDependencies);
- logger.debug(`added '${contextDependencies}' as a context dependency`);
- glob = path.isAbsolute(originalFrom) ? originalFrom : path.posix.join(getFastGlob().escapePath(getNormalizePath()(path.resolve(pattern.context))), originalFrom);
- }
- }
- logger.log(`begin globbing '${glob}'...`);
- /**
- * @type {GlobEntry[]}
- */
- let globEntries;
- try {
- globEntries = await globby(glob, globOptions);
- } catch (error) {
- compilation.errors.push( /** @type {WebpackError} */error);
- return;
- }
- if (globEntries.length === 0) {
- if (pattern.noErrorOnMissing) {
- logger.log(`finished to process a pattern from '${normalizedOriginalFrom}' using '${pattern.context}' context to '${pattern.to}'`);
- return;
- }
- const missingError = new Error(`unable to locate '${glob}' glob`);
- compilation.errors.push( /** @type {WebpackError} */missingError);
- return;
- }
- /**
- * @type {Array<CopiedResult | undefined>}
- */
- let copiedResult;
- try {
- copiedResult = await Promise.all(globEntries.map(
- /**
- * @param {GlobEntry} globEntry
- * @returns {Promise<CopiedResult | undefined>}
- */
- async globEntry => {
- // Exclude directories
- if (!globEntry.dirent.isFile()) {
- return;
- }
- if (pattern.filter) {
- let isFiltered;
- try {
- isFiltered = await pattern.filter(globEntry.path);
- } catch (error) {
- compilation.errors.push( /** @type {WebpackError} */error);
- return;
- }
- if (!isFiltered) {
- logger.log(`skip '${globEntry.path}', because it was filtered`);
- return;
- }
- }
- const from = globEntry.path;
- logger.debug(`found '${from}'`);
- // `globby`/`fast-glob` return the relative path when the path contains special characters on windows
- const absoluteFilename = path.resolve(pattern.context, from);
- const to = typeof pattern.to === "function" ? await pattern.to({
- context: pattern.context,
- absoluteFilename
- }) : path.normalize(typeof pattern.to !== "undefined" ? pattern.to : "");
- const toType = pattern.toType ? pattern.toType : template.test(to) ? "template" : path.extname(to) === "" || to.slice(-1) === path.sep ? "dir" : "file";
- logger.log(`'to' option '${to}' determinated as '${toType}'`);
- const relativeFrom = path.relative(pattern.context, absoluteFilename);
- let filename = toType === "dir" ? path.join(to, relativeFrom) : to;
- if (path.isAbsolute(filename)) {
- filename = path.relative( /** @type {string} */compiler.options.output.path, filename);
- }
- logger.log(`determined that '${from}' should write to '${filename}'`);
- const sourceFilename = getNormalizePath()(path.relative(compiler.context, absoluteFilename));
- // If this came from a glob or dir, add it to the file dependencies
- if (fromType === "dir" || fromType === "glob") {
- compilation.fileDependencies.add(absoluteFilename);
- logger.debug(`added '${absoluteFilename}' as a file dependency`);
- }
- let cacheEntry;
- logger.debug(`getting cache for '${absoluteFilename}'...`);
- try {
- cacheEntry = await cache.getPromise(`${sourceFilename}|${index}`, null);
- } catch (error) {
- compilation.errors.push( /** @type {WebpackError} */error);
- return;
- }
- /**
- * @type {Asset["source"] | undefined}
- */
- let source;
- if (cacheEntry) {
- logger.debug(`found cache for '${absoluteFilename}'...`);
- let isValidSnapshot;
- logger.debug(`checking snapshot on valid for '${absoluteFilename}'...`);
- try {
- isValidSnapshot = await CopyPlugin.checkSnapshotValid(compilation, cacheEntry.snapshot);
- } catch (error) {
- compilation.errors.push( /** @type {WebpackError} */error);
- return;
- }
- if (isValidSnapshot) {
- logger.debug(`snapshot for '${absoluteFilename}' is valid`);
- ({
- source
- } = cacheEntry);
- } else {
- logger.debug(`snapshot for '${absoluteFilename}' is invalid`);
- }
- } else {
- logger.debug(`missed cache for '${absoluteFilename}'`);
- }
- if (!source) {
- const startTime = Date.now();
- logger.debug(`reading '${absoluteFilename}'...`);
- let data;
- try {
- data = await readFile(inputFileSystem, absoluteFilename);
- } catch (error) {
- compilation.errors.push( /** @type {WebpackError} */error);
- return;
- }
- logger.debug(`read '${absoluteFilename}'`);
- source = new RawSource(data);
- let snapshot;
- logger.debug(`creating snapshot for '${absoluteFilename}'...`);
- try {
- snapshot = await CopyPlugin.createSnapshot(compilation, startTime, absoluteFilename);
- } catch (error) {
- compilation.errors.push( /** @type {WebpackError} */error);
- return;
- }
- if (snapshot) {
- logger.debug(`created snapshot for '${absoluteFilename}'`);
- logger.debug(`storing cache for '${absoluteFilename}'...`);
- try {
- await cache.storePromise(`${sourceFilename}|${index}`, null, {
- source,
- snapshot
- });
- } catch (error) {
- compilation.errors.push( /** @type {WebpackError} */error);
- return;
- }
- logger.debug(`stored cache for '${absoluteFilename}'`);
- }
- }
- if (pattern.transform) {
- /**
- * @type {TransformerObject}
- */
- const transformObj = typeof pattern.transform === "function" ? {
- transformer: pattern.transform
- } : pattern.transform;
- if (transformObj.transformer) {
- logger.log(`transforming content for '${absoluteFilename}'...`);
- const buffer = source.buffer();
- if (transformObj.cache) {
- // TODO: remove in the next major release
- const hasher = compiler.webpack && compiler.webpack.util && compiler.webpack.util.createHash ? compiler.webpack.util.createHash("xxhash64") :
- // eslint-disable-next-line global-require
- require("crypto").createHash("md4");
- const defaultCacheKeys = {
- version,
- sourceFilename,
- transform: transformObj.transformer,
- contentHash: hasher.update(buffer).digest("hex"),
- index
- };
- const cacheKeys = `transform|${getSerializeJavascript()(typeof transformObj.cache === "boolean" ? defaultCacheKeys : typeof transformObj.cache.keys === "function" ? await transformObj.cache.keys(defaultCacheKeys, absoluteFilename) : {
- ...defaultCacheKeys,
- ...transformObj.cache.keys
- })}`;
- logger.debug(`getting transformation cache for '${absoluteFilename}'...`);
- const cacheItem = cache.getItemCache(cacheKeys, cache.getLazyHashedEtag(source));
- source = await cacheItem.getPromise();
- logger.debug(source ? `found transformation cache for '${absoluteFilename}'` : `no transformation cache for '${absoluteFilename}'`);
- if (!source) {
- const transformed = await transformObj.transformer(buffer, absoluteFilename);
- source = new RawSource(transformed);
- logger.debug(`caching transformation for '${absoluteFilename}'...`);
- await cacheItem.storePromise(source);
- logger.debug(`cached transformation for '${absoluteFilename}'`);
- }
- } else {
- source = new RawSource(await transformObj.transformer(buffer, absoluteFilename));
- }
- }
- }
- let info = typeof pattern.info === "undefined" ? {} : typeof pattern.info === "function" ? pattern.info({
- absoluteFilename,
- sourceFilename,
- filename,
- toType
- }) || {} : pattern.info || {};
- if (toType === "template") {
- logger.log(`interpolating template '${filename}' for '${sourceFilename}'...`);
- const contentHash = CopyPlugin.getContentHash(compiler, compilation, source.buffer());
- const ext = path.extname(sourceFilename);
- const base = path.basename(sourceFilename);
- const name = base.slice(0, base.length - ext.length);
- const data = {
- filename: getNormalizePath()(path.relative(pattern.context, absoluteFilename)),
- contentHash,
- chunk: {
- name,
- id: ( /** @type {string} */sourceFilename),
- hash: contentHash
- }
- };
- const {
- path: interpolatedFilename,
- info: assetInfo
- } = compilation.getPathWithInfo(getNormalizePath()(filename), data);
- info = {
- ...info,
- ...assetInfo
- };
- filename = interpolatedFilename;
- logger.log(`interpolated template '${filename}' for '${sourceFilename}'`);
- } else {
- filename = getNormalizePath()(filename);
- }
- // eslint-disable-next-line consistent-return
- return {
- sourceFilename,
- absoluteFilename,
- filename,
- source,
- info,
- force: pattern.force
- };
- }));
- } catch (error) {
- compilation.errors.push( /** @type {WebpackError} */error);
- return;
- }
- if (copiedResult.length === 0) {
- if (pattern.noErrorOnMissing) {
- logger.log(`finished to process a pattern from '${normalizedOriginalFrom}' using '${pattern.context}' context to '${pattern.to}'`);
- return;
- }
- const missingError = new Error(`unable to locate '${glob}' glob after filtering paths`);
- compilation.errors.push( /** @type {WebpackError} */missingError);
- return;
- }
- logger.log(`finished to process a pattern from '${normalizedOriginalFrom}' using '${pattern.context}' context`);
- // eslint-disable-next-line consistent-return
- return copiedResult;
- }
- /**
- * @param {Compiler} compiler
- */
- apply(compiler) {
- const pluginName = this.constructor.name;
- compiler.hooks.thisCompilation.tap(pluginName, compilation => {
- const logger = compilation.getLogger("copy-webpack-plugin");
- const cache = compilation.getCache("CopyWebpackPlugin");
- /**
- * @type {typeof import("globby").globby}
- */
- let globby;
- compilation.hooks.processAssets.tapAsync({
- name: "copy-webpack-plugin",
- stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL
- }, async (unusedAssets, callback) => {
- if (typeof globby === "undefined") {
- try {
- globby = await getGlobby();
- } catch (error) {
- callback( /** @type {Error} */error);
- return;
- }
- }
- logger.log("starting to add additional assets...");
- const copiedResultMap = new Map();
- /**
- * @type {(() => Promise<void>)[]}
- */
- const scheduledTasks = [];
- this.patterns.map(
- /**
- * @param {Pattern} item
- * @param {number} index
- * @return {number}
- */
- (item, index) => scheduledTasks.push(async () => {
- /**
- * @type {ObjectPattern}
- */
- const normalizedPattern = typeof item === "string" ? {
- from: item
- } : {
- ...item
- };
- const context = typeof normalizedPattern.context === "undefined" ? compiler.context : path.isAbsolute(normalizedPattern.context) ? normalizedPattern.context : path.join(compiler.context, normalizedPattern.context);
- normalizedPattern.context = context;
- /**
- * @type {Array<CopiedResult | undefined> | undefined}
- */
- let copiedResult;
- try {
- copiedResult = await CopyPlugin.runPattern(globby, compiler, compilation, logger, cache, /** @type {ObjectPattern & { context: string }} */
- normalizedPattern, index);
- } catch (error) {
- compilation.errors.push( /** @type {WebpackError} */error);
- return;
- }
- if (!copiedResult) {
- return;
- }
- /**
- * @type {Array<CopiedResult>}
- */
- let filteredCopiedResult = copiedResult.filter(
- /**
- * @param {CopiedResult | undefined} result
- * @returns {result is CopiedResult}
- */
- result => Boolean(result));
- if (typeof normalizedPattern.transformAll !== "undefined") {
- if (typeof normalizedPattern.to === "undefined") {
- compilation.errors.push( /** @type {WebpackError} */
- new Error(`Invalid "pattern.to" for the "pattern.from": "${normalizedPattern.from}" and "pattern.transformAll" function. The "to" option must be specified.`));
- return;
- }
- filteredCopiedResult.sort((a, b) => a.absoluteFilename > b.absoluteFilename ? 1 : a.absoluteFilename < b.absoluteFilename ? -1 : 0);
- const mergedEtag = filteredCopiedResult.length === 1 ? cache.getLazyHashedEtag(filteredCopiedResult[0].source) : filteredCopiedResult.reduce(
- /**
- * @param {Etag} accumulator
- * @param {CopiedResult} asset
- * @param {number} i
- * @return {Etag}
- */
- // @ts-ignore
- (accumulator, asset, i) => {
- // eslint-disable-next-line no-param-reassign
- accumulator = cache.mergeEtags(i === 1 ? cache.getLazyHashedEtag( /** @type {CopiedResult}*/accumulator.source) : accumulator, cache.getLazyHashedEtag(asset.source));
- return accumulator;
- });
- const cacheItem = cache.getItemCache(`transformAll|${getSerializeJavascript()({
- version,
- from: normalizedPattern.from,
- to: normalizedPattern.to,
- transformAll: normalizedPattern.transformAll
- })}`, mergedEtag);
- let transformedAsset = await cacheItem.getPromise();
- if (!transformedAsset) {
- transformedAsset = {
- filename: normalizedPattern.to
- };
- try {
- transformedAsset.data = await normalizedPattern.transformAll(filteredCopiedResult.map(asset => {
- return {
- data: asset.source.buffer(),
- sourceFilename: asset.sourceFilename,
- absoluteFilename: asset.absoluteFilename
- };
- }));
- } catch (error) {
- compilation.errors.push( /** @type {WebpackError} */error);
- return;
- }
- const filename = typeof normalizedPattern.to === "function" ? await normalizedPattern.to({
- context
- }) : normalizedPattern.to;
- if (template.test(filename)) {
- const contentHash = CopyPlugin.getContentHash(compiler, compilation, transformedAsset.data);
- const {
- path: interpolatedFilename,
- info: assetInfo
- } = compilation.getPathWithInfo(getNormalizePath()(filename), {
- contentHash,
- chunk: {
- id: "unknown-copied-asset",
- hash: contentHash
- }
- });
- transformedAsset.filename = interpolatedFilename;
- transformedAsset.info = assetInfo;
- }
- const {
- RawSource
- } = compiler.webpack.sources;
- transformedAsset.source = new RawSource(transformedAsset.data);
- transformedAsset.force = normalizedPattern.force;
- await cacheItem.storePromise(transformedAsset);
- }
- filteredCopiedResult = [transformedAsset];
- }
- const priority = normalizedPattern.priority || 0;
- if (!copiedResultMap.has(priority)) {
- copiedResultMap.set(priority, []);
- }
- copiedResultMap.get(priority).push(...filteredCopiedResult);
- }));
- await throttleAll(this.options.concurrency || 100, scheduledTasks);
- const copiedResult = [...copiedResultMap.entries()].sort((a, b) => a[0] - b[0]);
- // Avoid writing assets inside `p-limit`, because it creates concurrency.
- // It could potentially lead to an error - 'Multiple assets emit different content to the same filename'
- copiedResult.reduce((acc, val) => acc.concat(val[1]), []).filter(Boolean).forEach(
- /**
- * @param {CopiedResult} result
- * @returns {void}
- */
- result => {
- const {
- absoluteFilename,
- sourceFilename,
- filename,
- source,
- force
- } = result;
- const existingAsset = compilation.getAsset(filename);
- if (existingAsset) {
- if (force) {
- const info = {
- copied: true,
- sourceFilename
- };
- logger.log(`force updating '${filename}' from '${absoluteFilename}' to compilation assets, because it already exists...`);
- compilation.updateAsset(filename, source, {
- ...info,
- ...result.info
- });
- logger.log(`force updated '${filename}' from '${absoluteFilename}' to compilation assets, because it already exists`);
- return;
- }
- logger.log(`skip adding '${filename}' from '${absoluteFilename}' to compilation assets, because it already exists`);
- return;
- }
- const info = {
- copied: true,
- sourceFilename
- };
- logger.log(`writing '${filename}' from '${absoluteFilename}' to compilation assets...`);
- compilation.emitAsset(filename, source, {
- ...info,
- ...result.info
- });
- logger.log(`written '${filename}' from '${absoluteFilename}' to compilation assets`);
- });
- logger.log("finished to adding additional assets");
- callback();
- });
- if (compilation.hooks.statsPrinter) {
- compilation.hooks.statsPrinter.tap(pluginName, stats => {
- stats.hooks.print.for("asset.info.copied").tap("copy-webpack-plugin", (copied, {
- green,
- formatFlag
- }) => copied ? /** @type {Function} */green( /** @type {Function} */formatFlag("copied")) : "");
- });
- }
- });
- }
- }
- module.exports = CopyPlugin;
|