Files
bedrock/assets/build/webpack.plugin.copyglobs.js
QWp6t 4adbc347c2 Fix browsersync (#1815)
* Update dependencies
* Remove monkey-hot-loader
* Use webpack-merge instead of util/mergeWithConcat()
* Fix: copyglobs plugin `after-emit` is bound twice
* NoErrorsPlugin() is deprecated in favor of NoEmitOnErrorsPlugin()
* webpack-dev-middleware should use same publicPath as compiler
* webpack-hot-middleware/client should be prepended to entries
* Browser should refresh when HMR fails
* Bootstrap package.json has correct main property
Sometime between alpha 2 and 3, package.json was pointing to nonexistent
file, so we referenced file manually in our repo. Underlying issue was
fixed by alpha 4, so we no longer have to specify full path to file.
2017-01-18 23:58:37 -08:00

148 lines
4.3 KiB
JavaScript

'use strict'; // eslint-disable-line
const fs = require('fs');
const path = require('path');
const glob = require('glob');
const utils = require('loader-utils');
const includes = require('lodash/includes');
const interpolateName = require('./util/interpolateName');
const promisify = require('./util/promisify');
const fixPath = v => v.replace(/\\/g, '/');
const errorMsg = msg => `\x1b[31m${msg}\x1b[0m`;
const GLOB_CWD_AUTO = null;
const globAsync = promisify(glob);
const statAsync = promisify(fs.stat);
const readFileAsync = promisify(fs.readFile);
class PatternUndefinedError extends Error {
constructor() {
super(errorMsg('[copy-globs] You must provide glob pattern.'));
}
}
class ArgsArrayError extends TypeError {
constructor() {
super(errorMsg(
'[copy-globs] pattern cannot be an array.\n' +
'For multiple folders, use something like:\n\n' +
' +(images|fonts)/**/*\n\n' +
'See also: https://github.com/isaacs/node-glob#glob-primer\n'
));
}
}
/**
* Throws an error if pattern is an array or undefined
*
* @param pattern
*/
const testPattern = (pattern) => {
if (pattern === undefined) {
throw new PatternUndefinedError();
}
if (Array.isArray(pattern)) {
throw new ArgsArrayError();
}
};
const normalizeArguments = (input) => {
testPattern(input);
const options = {};
if (typeof input === 'string') {
options.pattern = input;
} else {
testPattern(input.pattern);
return input;
}
return options;
};
module.exports = class {
constructor(o) {
const options = normalizeArguments(o);
this.pattern = options.pattern;
this.disable = options.disable;
this.output = options.output || '[path][name].[ext]';
this.globOptions = Object.assign(options.globOptions || {}, { cwd: GLOB_CWD_AUTO });
this.globOptions.nodir = true;
this.manifest = options.manifest || {};
this.files = [];
this.started = false;
}
apply(compiler) {
if (this.disable) {
return;
}
this.compiler = compiler;
this.resolveWorkingDirectory();
if (!this.started) {
compiler.plugin('emit', this.emitHandler.bind(this));
compiler.plugin('after-emit', this.afterEmitHandler.bind(this));
this.started = true;
}
}
emitHandler(compilation, callback) {
this.compilation = compilation;
globAsync(this.pattern, this.globOptions)
.then(
paths => Promise.all(paths.map(this.processAsset.bind(this))),
err => compilation.errors.push(err)
)
.then(() => {
Object.keys(this.files).forEach((absoluteFrom) => {
const file = this.files[absoluteFrom];
this.manifest[file.relativeFrom] = file.webpackTo;
this.compilation.assets[file.webpackTo] = {
size: () => file.stat.size,
source: () => file.content,
};
});
})
.then(callback);
}
afterEmitHandler(compilation, callback) {
Object.keys(this.files)
.filter(absoluteFrom => !includes(compilation.fileDependencies, absoluteFrom))
.forEach(absoluteFrom => compilation.fileDependencies.push(absoluteFrom));
callback();
}
resolveWorkingDirectory() {
if (this.globOptions.cwd === GLOB_CWD_AUTO) {
this.globOptions.cwd = this.compiler.options.context;
}
this.context = this.globOptions.cwd || this.compiler.options.context;
}
processAsset(relativeFrom) {
if (this.compilation.assets[relativeFrom]) {
return Promise.resolve();
}
const absoluteFrom = path.resolve(this.context, relativeFrom);
return statAsync(absoluteFrom)
.then(stat => this.buildFileObject(relativeFrom, absoluteFrom, stat))
.then(this.addAsset.bind(this));
}
buildFileObject(relativeFrom, absoluteFrom, stat) {
return readFileAsync(absoluteFrom)
.then((content) => {
const hash = utils.getHashDigest(content);
const webpackTo = fixPath(interpolateName(this.output, relativeFrom, content));
return { relativeFrom, absoluteFrom, stat, content, hash, webpackTo };
});
}
addAsset(file) {
const asset = this.getAsset(file.absoluteFrom);
if (asset && asset.hash === file.hash) {
return null;
}
this.files[file.absoluteFrom] = file;
return file;
}
getAsset(absoluteFrom) {
return this.files[absoluteFrom];
}
};