123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582 |
- const crypto = require('crypto');
- const fs = require('graceful-fs');
- const path = require('path');
- const lodash = require('lodash');
- const _mkdirp = require('mkdirp');
- const _rimraf = require('rimraf');
- const nodeObjectHash = require('node-object-hash');
- const findCacheDir = require('find-cache-dir');
- const envHash = require('./lib/envHash');
- const defaultConfigHash = require('./lib/defaultConfigHash');
- const promisify = require('./lib/util/promisify');
- const relateContext = require('./lib/util/relate-context');
- const pluginCompat = require('./lib/util/plugin-compat');
- const logMessages = require('./lib/util/log-messages');
- const LoggerFactory = require('./lib/loggerFactory');
- const cachePrefix = require('./lib/util').cachePrefix;
- const CacheSerializerFactory = require('./lib/CacheSerializerFactory');
- const ExcludeModulePlugin = require('./lib/ExcludeModulePlugin');
- const HardSourceLevelDbSerializerPlugin = require('./lib/SerializerLeveldbPlugin');
- const SerializerAppend2Plugin = require('./lib/SerializerAppend2Plugin');
- const SerializerAppendPlugin = require('./lib/SerializerAppendPlugin');
- const SerializerCacachePlugin = require('./lib/SerializerCacachePlugin');
- const SerializerJsonPlugin = require('./lib/SerializerJsonPlugin');
- const hardSourceVersion = require('./package.json').version;
- function requestHash(request) {
- return crypto
- .createHash('sha1')
- .update(request)
- .digest()
- .hexSlice();
- }
- const mkdirp = promisify(_mkdirp, { context: _mkdirp });
- mkdirp.sync = _mkdirp.sync.bind(_mkdirp);
- const rimraf = promisify(_rimraf);
- rimraf.sync = _rimraf.sync.bind(_rimraf);
- const fsReadFile = promisify(fs.readFile, { context: fs });
- const fsWriteFile = promisify(fs.writeFile, { context: fs });
- const bulkFsTask = (array, each) =>
- new Promise((resolve, reject) => {
- let ops = 0;
- const out = [];
- array.forEach((item, i) => {
- out[i] = each(item, (back, callback) => {
- ops++;
- return (err, value) => {
- try {
- out[i] = back(err, value, out[i]);
- } catch (e) {
- return reject(e);
- }
- ops--;
- if (ops === 0) {
- resolve(out);
- }
- };
- });
- });
- if (ops === 0) {
- resolve(out);
- }
- });
- const compilerContext = relateContext.compilerContext;
- const relateNormalPath = relateContext.relateNormalPath;
- const contextNormalPath = relateContext.contextNormalPath;
- const contextNormalPathSet = relateContext.contextNormalPathSet;
- function relateNormalRequest(compiler, key) {
- return key
- .split('!')
- .map(subkey => relateNormalPath(compiler, subkey))
- .join('!');
- }
- function relateNormalModuleId(compiler, id) {
- return id.substring(0, 24) + relateNormalRequest(compiler, id.substring(24));
- }
- function contextNormalRequest(compiler, key) {
- return key
- .split('!')
- .map(subkey => contextNormalPath(compiler, subkey))
- .join('!');
- }
- function contextNormalModuleId(compiler, id) {
- return id.substring(0, 24) + contextNormalRequest(compiler, id.substring(24));
- }
- function contextNormalLoaders(compiler, loaders) {
- return loaders.map(loader =>
- Object.assign({}, loader, {
- loader: contextNormalPath(compiler, loader.loader),
- }),
- );
- }
- function contextNormalPathArray(compiler, paths) {
- return paths.map(subpath => contextNormalPath(compiler, subpath));
- }
- class HardSourceWebpackPlugin {
- constructor(options) {
- this.options = options || {};
- }
- getPath(dirName, suffix) {
- const confighashIndex = dirName.search(/\[confighash\]/);
- if (confighashIndex !== -1) {
- dirName = dirName.replace(/\[confighash\]/, this.configHash);
- }
- let cachePath = path.resolve(
- process.cwd(),
- this.compilerOutputOptions.path,
- dirName,
- );
- if (suffix) {
- cachePath = path.join(cachePath, suffix);
- }
- return cachePath;
- }
- getCachePath(suffix) {
- return this.getPath(this.options.cacheDirectory, suffix);
- }
- apply(compiler) {
- const options = this.options;
- let active = true;
- const logger = new LoggerFactory(compiler).create();
- const loggerCore = logger.from('core');
- logger.lock();
- const compilerHooks = pluginCompat.hooks(compiler);
- if (!compiler.options.cache) {
- compiler.options.cache = true;
- }
- if (!options.cacheDirectory) {
- options.cacheDirectory = path.resolve(
- findCacheDir({
- name: 'hard-source',
- cwd: compiler.options.context || process.cwd(),
- }),
- '[confighash]',
- );
- }
- this.compilerOutputOptions = compiler.options.output;
- if (!options.configHash) {
- options.configHash = defaultConfigHash;
- }
- if (options.configHash) {
- if (typeof options.configHash === 'string') {
- this.configHash = options.configHash;
- } else if (typeof options.configHash === 'function') {
- this.configHash = options.configHash(compiler.options);
- }
- compiler.__hardSource_configHash = this.configHash;
- compiler.__hardSource_shortConfigHash = this.configHash.substring(0, 8);
- }
- const configHashInDirectory =
- options.cacheDirectory.search(/\[confighash\]/) !== -1;
- if (configHashInDirectory && !this.configHash) {
- logMessages.configHashSetButNotUsed(compiler, {
- cacheDirectory: options.cacheDirectory,
- });
- active = false;
- function unlockLogger() {
- logger.unlock();
- }
- compilerHooks.watchRun.tap('HardSource - index', unlockLogger);
- compilerHooks.run.tap('HardSource - index', unlockLogger);
- return;
- }
- let environmentHasher = null;
- if (typeof options.environmentHash !== 'undefined') {
- if (options.environmentHash === false) {
- environmentHasher = () => Promise.resolve('');
- } else if (typeof options.environmentHash === 'string') {
- environmentHasher = () => Promise.resolve(options.environmentHash);
- } else if (typeof options.environmentHash === 'object') {
- environmentHasher = () => envHash(options.environmentHash);
- environmentHasher.inputs = () =>
- envHash.inputs(options.environmentHash);
- } else if (typeof options.environmentHash === 'function') {
- environmentHasher = () => Promise.resolve(options.environmentHash());
- if (options.environmentHash.inputs) {
- environmentHasher.inputs = () =>
- Promise.resolve(options.environmentHasher.inputs());
- }
- }
- }
- if (!environmentHasher) {
- environmentHasher = envHash;
- }
- const cacheDirPath = this.getCachePath();
- const cacheAssetDirPath = path.join(cacheDirPath, 'assets');
- const resolveCachePath = path.join(cacheDirPath, 'resolve.json');
- let currentStamp = '';
- const cacheSerializerFactory = new CacheSerializerFactory(compiler);
- let createSerializers = true;
- let cacheRead = false;
- const _this = this;
- pluginCompat.register(compiler, '_hardSourceCreateSerializer', 'sync', [
- 'cacheSerializerFactory',
- 'cacheDirPath',
- ]);
- pluginCompat.register(compiler, '_hardSourceResetCache', 'sync', []);
- pluginCompat.register(compiler, '_hardSourceReadCache', 'asyncParallel', [
- 'relativeHelpers',
- ]);
- pluginCompat.register(
- compiler,
- '_hardSourceVerifyCache',
- 'asyncParallel',
- [],
- );
- pluginCompat.register(compiler, '_hardSourceWriteCache', 'asyncParallel', [
- 'compilation',
- 'relativeHelpers',
- ]);
- if (configHashInDirectory) {
- const PruneCachesSystem = require('./lib/SystemPruneCaches');
- new PruneCachesSystem(
- path.dirname(cacheDirPath),
- options.cachePrune,
- ).apply(compiler);
- }
- function runReadOrReset(_compiler) {
- logger.unlock();
- if (!active) {
- return Promise.resolve();
- }
- try {
- fs.statSync(cacheAssetDirPath);
- } catch (_) {
- mkdirp.sync(cacheAssetDirPath);
- logMessages.configHashFirstBuild(compiler, {
- cacheDirPath,
- configHash: compiler.__hardSource_configHash,
- });
- }
- const start = Date.now();
- if (createSerializers) {
- createSerializers = false;
- try {
- compilerHooks._hardSourceCreateSerializer.call(
- cacheSerializerFactory,
- cacheDirPath,
- );
- } catch (err) {
- return Promise.reject(err);
- }
- }
- return Promise.all([
- fsReadFile(path.join(cacheDirPath, 'stamp'), 'utf8').catch(() => ''),
- environmentHasher(),
- fsReadFile(path.join(cacheDirPath, 'version'), 'utf8').catch(() => ''),
- environmentHasher.inputs ? environmentHasher.inputs() : null,
- ]).then(([stamp, hash, versionStamp, hashInputs]) => {
- if (!configHashInDirectory && options.configHash) {
- hash += `_${_this.configHash}`;
- }
- if (hashInputs && !cacheRead) {
- logMessages.environmentInputs(compiler, { inputs: hashInputs });
- }
- currentStamp = hash;
- if (!hash || hash !== stamp || hardSourceVersion !== versionStamp) {
- if (hash && stamp) {
- if (configHashInDirectory) {
- logMessages.environmentHashChanged(compiler);
- } else {
- logMessages.configHashChanged(compiler);
- }
- } else if (versionStamp && hardSourceVersion !== versionStamp) {
- logMessages.hardSourceVersionChanged(compiler);
- }
- // Reset the cache, we can't use it do to an environment change.
- pluginCompat.call(compiler, '_hardSourceResetCache', []);
- return rimraf(cacheDirPath);
- }
- if (cacheRead) {
- return Promise.resolve();
- }
- cacheRead = true;
- logMessages.configHashBuildWith(compiler, {
- cacheDirPath,
- configHash: compiler.__hardSource_configHash,
- });
- function contextKeys(compiler, fn) {
- return source => {
- const dest = {};
- Object.keys(source).forEach(key => {
- dest[fn(compiler, key)] = source[key];
- });
- return dest;
- };
- }
- function contextValues(compiler, fn) {
- return source => {
- const dest = {};
- Object.keys(source).forEach(key => {
- const value = fn(compiler, source[key], key);
- if (value) {
- dest[key] = value;
- } else {
- delete dest[key];
- }
- });
- return dest;
- };
- }
- function copyWithDeser(dest, source) {
- Object.keys(source).forEach(key => {
- const item = source[key];
- dest[key] = typeof item === 'string' ? JSON.parse(item) : item;
- });
- }
- return Promise.all([
- compilerHooks._hardSourceReadCache.promise({
- contextKeys,
- contextValues,
- contextNormalPath,
- contextNormalRequest,
- contextNormalModuleId,
- copyWithDeser,
- }),
- ])
- .catch(error => {
- logMessages.serialBadCache(compiler, error);
- return rimraf(cacheDirPath);
- })
- .then(() => {
- // console.log('cache in', Date.now() - start);
- });
- });
- }
- compilerHooks.watchRun.tapPromise(
- 'HardSource - index - readOrReset',
- runReadOrReset,
- );
- compilerHooks.run.tapPromise(
- 'HardSource - index - readOrReset',
- runReadOrReset,
- );
- const detectModule = path => {
- try {
- require(path);
- return true;
- } catch (_) {
- return false;
- }
- };
- const webpackFeatures = {
- concatenatedModule: detectModule(
- 'webpack/lib/optimize/ConcatenatedModule',
- ),
- generator: detectModule('webpack/lib/JavascriptGenerator'),
- };
- let schemasVersion = 2;
- if (webpackFeatures.concatenatedModule) {
- schemasVersion = 3;
- }
- if (webpackFeatures.generator) {
- schemasVersion = 4;
- }
- const ArchetypeSystem = require('./lib/SystemArchetype');
- const ParitySystem = require('./lib/SystemParity');
- const AssetCache = require('./lib/CacheAsset');
- const ModuleCache = require('./lib/CacheModule');
- const EnhancedResolveCache = require('./lib/CacheEnhancedResolve');
- const Md5Cache = require('./lib/CacheMd5');
- const ModuleResolverCache = require('./lib/CacheModuleResolver');
- const TransformCompilationPlugin = require('./lib/TransformCompilationPlugin');
- const TransformAssetPlugin = require('./lib/TransformAssetPlugin');
- let TransformConcatenationModulePlugin;
- if (webpackFeatures.concatenatedModule) {
- TransformConcatenationModulePlugin = require('./lib/TransformConcatenationModulePlugin');
- }
- const TransformNormalModulePlugin = require('./lib/TransformNormalModulePlugin');
- const TransformNormalModuleFactoryPlugin = require('./lib/TransformNormalModuleFactoryPlugin');
- const TransformModuleAssetsPlugin = require('./lib/TransformModuleAssetsPlugin');
- const TransformModuleErrorsPlugin = require('./lib/TransformModuleErrorsPlugin');
- const SupportExtractTextPlugin = require('./lib/SupportExtractTextPlugin');
- let SupportMiniCssExtractPlugin;
- if (webpackFeatures.generator) {
- SupportMiniCssExtractPlugin = require('./lib/SupportMiniCssExtractPlugin');
- }
- const TransformDependencyBlockPlugin = require('./lib/TransformDependencyBlockPlugin');
- const TransformBasicDependencyPlugin = require('./lib/TransformBasicDependencyPlugin');
- let HardHarmonyDependencyPlugin;
- const TransformSourcePlugin = require('./lib/TransformSourcePlugin');
- const TransformParserPlugin = require('./lib/TransformParserPlugin');
- let TransformGeneratorPlugin;
- if (webpackFeatures.generator) {
- TransformGeneratorPlugin = require('./lib/TransformGeneratorPlugin');
- }
- const ChalkLoggerPlugin = require('./lib/ChalkLoggerPlugin');
- new ArchetypeSystem().apply(compiler);
- new ParitySystem().apply(compiler);
- new AssetCache().apply(compiler);
- new ModuleCache().apply(compiler);
- new EnhancedResolveCache().apply(compiler);
- new Md5Cache().apply(compiler);
- new ModuleResolverCache().apply(compiler);
- new TransformCompilationPlugin().apply(compiler);
- new TransformAssetPlugin().apply(compiler);
- new TransformNormalModulePlugin({
- schema: schemasVersion,
- }).apply(compiler);
- new TransformNormalModuleFactoryPlugin().apply(compiler);
- if (TransformConcatenationModulePlugin) {
- new TransformConcatenationModulePlugin().apply(compiler);
- }
- new TransformModuleAssetsPlugin().apply(compiler);
- new TransformModuleErrorsPlugin().apply(compiler);
- new SupportExtractTextPlugin().apply(compiler);
- if (SupportMiniCssExtractPlugin) {
- new SupportMiniCssExtractPlugin().apply(compiler);
- }
- new TransformDependencyBlockPlugin({
- schema: schemasVersion,
- }).apply(compiler);
- new TransformBasicDependencyPlugin({
- schema: schemasVersion,
- }).apply(compiler);
- new TransformSourcePlugin({
- schema: schemasVersion,
- }).apply(compiler);
- new TransformParserPlugin({
- schema: schemasVersion,
- }).apply(compiler);
- if (TransformGeneratorPlugin) {
- new TransformGeneratorPlugin({
- schema: schemasVersion,
- }).apply(compiler);
- }
- new ChalkLoggerPlugin(this.options.info).apply(compiler);
- function runVerify(_compiler) {
- if (!active) {
- return Promise.resolve();
- }
- const stats = {};
- return pluginCompat.promise(compiler, '_hardSourceVerifyCache', []);
- }
- compilerHooks.watchRun.tapPromise('HardSource - index - verify', runVerify);
- compilerHooks.run.tapPromise('HardSource - index - verify', runVerify);
- let freeze;
- compilerHooks._hardSourceMethods.tap('HardSource - index', methods => {
- freeze = methods.freeze;
- });
- compilerHooks.afterCompile.tapPromise('HardSource - index', compilation => {
- if (!active) {
- return Promise.resolve();
- }
- const startCacheTime = Date.now();
- const identifierPrefix = cachePrefix(compilation);
- if (identifierPrefix !== null) {
- freeze('Compilation', null, compilation, {
- compilation,
- });
- }
- return Promise.all([
- mkdirp(cacheDirPath).then(() =>
- Promise.all([
- fsWriteFile(path.join(cacheDirPath, 'stamp'), currentStamp, 'utf8'),
- fsWriteFile(
- path.join(cacheDirPath, 'version'),
- hardSourceVersion,
- 'utf8',
- ),
- ]),
- ),
- pluginCompat.promise(compiler, '_hardSourceWriteCache', [
- compilation,
- {
- relateNormalPath,
- relateNormalRequest,
- relateNormalModuleId,
- contextNormalPath,
- contextNormalRequest,
- contextNormalModuleId,
- },
- ]),
- ]).then(() => {
- // console.log('cache out', Date.now() - startCacheTime);
- });
- });
- }
- }
- module.exports = HardSourceWebpackPlugin;
- HardSourceWebpackPlugin.ExcludeModulePlugin = ExcludeModulePlugin;
- HardSourceWebpackPlugin.HardSourceLevelDbSerializerPlugin = HardSourceLevelDbSerializerPlugin;
- HardSourceWebpackPlugin.LevelDbSerializerPlugin = HardSourceLevelDbSerializerPlugin;
- HardSourceWebpackPlugin.SerializerAppend2Plugin = SerializerAppend2Plugin;
- HardSourceWebpackPlugin.SerializerAppendPlugin = SerializerAppendPlugin;
- HardSourceWebpackPlugin.SerializerCacachePlugin = SerializerCacachePlugin;
- HardSourceWebpackPlugin.SerializerJsonPlugin = SerializerJsonPlugin;
- Object.defineProperty(HardSourceWebpackPlugin, 'ParallelModulePlugin', {
- get() {
- return require('./lib/ParallelModulePlugin');
- },
- });
|