Skip to content

Commit

Permalink
Use mini-css-extract-plugin@^0.6.0 and embed webpack-manifest-plugin …
Browse files Browse the repository at this point in the history
…into Encore
  • Loading branch information
Lyrkan committed Apr 13, 2019
1 parent ba08baf commit 92017f7
Show file tree
Hide file tree
Showing 8 changed files with 315 additions and 58 deletions.
1 change: 1 addition & 0 deletions .eslintignore
@@ -0,0 +1 @@
lib/webpack/webpack-manifest-plugin.js
2 changes: 1 addition & 1 deletion lib/plugins/manifest.js
Expand Up @@ -10,7 +10,7 @@
'use strict';

const WebpackConfig = require('../WebpackConfig'); //eslint-disable-line no-unused-vars
const ManifestPlugin = require('webpack-manifest-plugin');
const ManifestPlugin = require('../webpack/webpack-manifest-plugin');
const PluginPriorities = require('./plugin-priorities');
const applyOptionsCallback = require('../utils/apply-options-callback');
const sharedEntryTmpName = require('../utils/sharedEntryTmpName');
Expand Down
258 changes: 250 additions & 8 deletions lib/webpack/webpack-manifest-plugin.js
@@ -1,15 +1,257 @@
/*
* This file is part of the Symfony Webpack Encore package.
* This code is based on the "lib/plugin.js" file provided by the
* webpack-manifest-plugin@2.0.4 (https://github.com/danethurber/webpack-manifest-plugin)
*
* (c) Fabien Potencier <fabien@symfony.com>
* It adds the changes made by @karlvr in pull request #176 that
* allow the plugin to work with mini-css-extract-plugin > 0.4.2
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
* The library is licensed as MIT.
*/

'use strict';
var path = require('path');
var fse = require('fs-extra');
var _ = require('lodash');

const logger = require('../logger');
logger.deprecation('The lib/webpack/webpack-manifest-plugin.js module is deprecated: require the library directly now: require(\'webpack-manifest-plugin\').');
const emitCountMap = new Map();

module.exports = require('webpack-manifest-plugin');
function ManifestPlugin(opts) {
this.opts = _.assign({
publicPath: null,
basePath: '',
fileName: 'manifest.json',
transformExtensions: /^(gz|map)$/i,
writeToFileEmit: false,
seed: null,
filter: null,
map: null,
generate: null,
sort: null,
serialize: function(manifest) {
return JSON.stringify(manifest, null, 2);
},
}, opts || {});
}

ManifestPlugin.prototype.getFileType = function(str) {
str = str.replace(/\?.*/, '');
var split = str.split('.');
var ext = split.pop();
if (this.opts.transformExtensions.test(ext)) {
ext = split.pop() + '.' + ext;
}
return ext;
};

ManifestPlugin.prototype.apply = function(compiler) {
var moduleAssets = {};

var outputFolder = compiler.options.output.path;
var outputFile = path.resolve(outputFolder, this.opts.fileName);
var outputName = path.relative(outputFolder, outputFile);

var moduleAsset = function (module, file) {
if (module.userRequest) {
moduleAssets[file] = path.join(
path.dirname(file),
path.basename(module.userRequest)
);
}
};

var normalModuleLoader = function (loaderContext, module) {
const { emitFile } = loaderContext;

loaderContext.emitFile = (file, content, sourceMap) => {
if (module.userRequest && !moduleAssets[file]) {
moduleAssets[file] = path.join(
path.dirname(file),
path.basename(module.userRequest)
);
}

return emitFile.call(module, file, content, sourceMap);
};
};

var emit = function(compilation, compileCallback) {
const emitCount = emitCountMap.get(outputFile) - 1
emitCountMap.set(outputFile, emitCount);

var seed = this.opts.seed || {};

var publicPath = this.opts.publicPath != null ? this.opts.publicPath : compilation.options.output.publicPath;
var stats = compilation.getStats().toJson();

var files = compilation.chunks.reduce(function(files, chunk) {
return chunk.files.reduce(function (files, path) {
var name = chunk.name ? chunk.name : null;

if (name) {
name = name + '.' + this.getFileType(path);
} else {
// For nameless chunks, just map the files directly.
name = path;
}

// Webpack 4: .isOnlyInitial()
// Webpack 3: .isInitial()
// Webpack 1/2: .initial
return files.concat({
path: path,
chunk: chunk,
name: name,
isInitial: chunk.isOnlyInitial ? chunk.isOnlyInitial() : (chunk.isInitial ? chunk.isInitial() : chunk.initial),
isChunk: true,
isAsset: false,
isModuleAsset: false
});
}.bind(this), files);
}.bind(this), []);

// module assets don't show up in assetsByChunkName.
// we're getting them this way;
files = stats.assets.reduce(function (files, asset) {
var name = moduleAssets[asset.name];
if (name) {
return files.concat({
path: asset.name,
name: name,
isInitial: false,
isChunk: false,
isAsset: true,
isModuleAsset: true
});
}

var isEntryAsset = asset.chunks.length > 0;
if (isEntryAsset) {
return files;
}

return files.concat({
path: asset.name,
name: asset.name,
isInitial: false,
isChunk: false,
isAsset: true,
isModuleAsset: false
});
}, files);

files = files.filter(function (file) {
// Don't add hot updates to manifest
var isUpdateChunk = file.path.indexOf('hot-update') >= 0;
// Don't add manifest from another instance
var isManifest = emitCountMap.get(path.join(outputFolder, file.name)) !== undefined;

return !isUpdateChunk && !isManifest;
});

// Append optional basepath onto all references.
// This allows output path to be reflected in the manifest.
if (this.opts.basePath) {
files = files.map(function(file) {
file.name = this.opts.basePath + file.name;
return file;
}.bind(this));
}

if (publicPath) {
// Similar to basePath but only affects the value (similar to how
// output.publicPath turns require('foo/bar') into '/public/foo/bar', see
// https://github.com/webpack/docs/wiki/configuration#outputpublicpath
files = files.map(function(file) {
file.path = publicPath + file.path;
return file;
}.bind(this));
}

files = files.map(file => {
file.name = file.name.replace(/\\/g, '/');
file.path = file.path.replace(/\\/g, '/');
return file;
});

if (this.opts.filter) {
files = files.filter(this.opts.filter);
}

if (this.opts.map) {
files = files.map(this.opts.map);
}

if (this.opts.sort) {
files = files.sort(this.opts.sort);
}

var manifest;
if (this.opts.generate) {
manifest = this.opts.generate(seed, files);
} else {
manifest = files.reduce(function (manifest, file) {
manifest[file.name] = file.path;
return manifest;
}, seed);
}

const isLastEmit = emitCount === 0
if (isLastEmit) {
var output = this.opts.serialize(manifest);

compilation.assets[outputName] = {
source: function() {
return output;
},
size: function() {
return output.length;
}
};

if (this.opts.writeToFileEmit) {
fse.outputFileSync(outputFile, output);
}
}

if (compiler.hooks) {
compiler.hooks.webpackManifestPluginAfterEmit.call(manifest);
} else {
compilation.applyPluginsAsync('webpack-manifest-plugin-after-emit', manifest, compileCallback);
}
}.bind(this);

function beforeRun (compiler, callback) {
let emitCount = emitCountMap.get(outputFile) || 0;
emitCountMap.set(outputFile, emitCount + 1);

if (callback) {
callback();
}
}

if (compiler.hooks) {
const SyncWaterfallHook = require('tapable').SyncWaterfallHook;
const pluginOptions = {
name: 'ManifestPlugin',
stage: Infinity
};
compiler.hooks.webpackManifestPluginAfterEmit = new SyncWaterfallHook(['manifest']);

compiler.hooks.compilation.tap(pluginOptions, function (compilation) {
compilation.hooks.normalModuleLoader.tap(pluginOptions, normalModuleLoader);
});
compiler.hooks.emit.tap(pluginOptions, emit);

compiler.hooks.run.tap(pluginOptions, beforeRun);
compiler.hooks.watchRun.tap(pluginOptions, beforeRun);
} else {
compiler.plugin('compilation', function (compilation) {
compilation.plugin('module-asset', moduleAsset);
});
compiler.plugin('emit', emit);

compiler.plugin('before-run', beforeRun);
compiler.plugin('watch-run', beforeRun);
}
};

module.exports = ManifestPlugin;
4 changes: 2 additions & 2 deletions package.json
Expand Up @@ -39,20 +39,20 @@
"fs-extra": "^2.0.0",
"loader-utils": "^1.1.0",
"lodash": ">=3.5 <5",
"mini-css-extract-plugin": ">=0.4.0 <0.4.3",
"mini-css-extract-plugin": "^0.6.0",
"optimize-css-assets-webpack-plugin": "^5.0.1",
"pkg-up": "^1.0.0",
"pretty-error": "^2.1.1",
"resolve-url-loader": "^3.0.1",
"semver": "^5.5.0",
"style-loader": "^0.21.0",
"tapable": "^1.0.0",
"terser-webpack-plugin": "^1.1.0",
"tmp": "^0.0.33",
"webpack": "^4.20.0",
"webpack-chunk-hash": "^0.6.0",
"webpack-cli": "^3.0.0",
"webpack-dev-server": "^3.1.14",
"webpack-manifest-plugin": "^2.0.2",
"webpack-sources": "^1.3.0",
"yargs-parser": "^12.0.0"
},
Expand Down
2 changes: 1 addition & 1 deletion test/config-generator.js
Expand Up @@ -14,7 +14,7 @@ const WebpackConfig = require('../lib/WebpackConfig');
const RuntimeConfig = require('../lib/config/RuntimeConfig');
const configGenerator = require('../lib/config-generator');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const ManifestPlugin = require('webpack-manifest-plugin');
const ManifestPlugin = require('../lib/webpack/webpack-manifest-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const webpack = require('webpack');
const path = require('path');
Expand Down

0 comments on commit 92017f7

Please sign in to comment.