Skip to content
This repository has been archived by the owner on May 29, 2019. It is now read-only.

fix: split async CSS correctly #546

Closed
wants to merge 28 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
77daf83
refactor: pass a unique compiler name to get child compilation (#483)
sokra Jun 11, 2017
92e4349
chore(package): Update peerDeps & webpack devDep
joshwiens Jun 11, 2017
cdfccb4
Squashed commit of the following:
BowlingX Jun 20, 2017
3e78452
refactor: Apply webpack-defaults (#542)
joshwiens Jun 21, 2017
4880afb
Merge remote-tracking branch 'base/feature/webpack3'
BowlingX Jun 21, 2017
5df5d09
fix(tests): fixed test to work with webpack 3, adjusted dependencies
BowlingX Jun 21, 2017
b202f4a
only remove dependencies that have loaders defined
BowlingX Jun 21, 2017
292e217
refactor: Apply webpack-defaults (#542)
joshwiens Jun 21, 2017
28171b2
refactor: Chunk.modules deprecation warning
joshwiens Jun 23, 2017
1730d46
chore(release): 3.0.0-beta.0
joshwiens Jun 23, 2017
5d0c28f
fix: Distribute schema with package
joshwiens Jun 24, 2017
715b1dd
chore(release): 3.0.0-beta.1
joshwiens Jun 24, 2017
1ef755a
chore: Update install docs
joshwiens Jun 24, 2017
84a0328
chore(release): 3.0.0-beta.2
joshwiens Jun 24, 2017
b33e006
chore(package): Update deps minor versions
joshwiens Jun 24, 2017
d4a0c23
chore(release): 3.0.0-beta.3
joshwiens Jun 24, 2017
10721f5
chore: Update changelog for beta 1 & 2
joshwiens Jun 24, 2017
1175e63
Merge remote-tracking branch 'base/feature/webpack3'
BowlingX Jun 26, 2017
fb4eb9b
fixed merge conflicts
BowlingX Jun 26, 2017
400ed49
Merge branch 'master-remote'
BowlingX Jul 21, 2017
143760a
fixed tests
BowlingX Jul 21, 2017
163191a
Merge remote-tracking branch 'base/master'
BowlingX Nov 29, 2017
2ba04eb
adjusted tests
BowlingX Nov 29, 2017
3ef2916
adjusted tests
BowlingX Nov 29, 2017
8403a27
fixed code style, moved clone to helpers
BowlingX Nov 29, 2017
3aed4df
code style fixes
BowlingX Mar 18, 2018
f1a8ce2
moved schema files to src, adjusted build.
BowlingX Mar 18, 2018
edd39a1
Merge remote-tracking branch 'upstream/master'
BowlingX Apr 5, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
82 changes: 66 additions & 16 deletions index.js
Expand Up @@ -7,6 +7,7 @@ var ConcatSource = require("webpack-sources").ConcatSource;
var async = require("async");
var ExtractedModule = require("./ExtractedModule");
var Chunk = require("webpack/lib/Chunk");
var NormalModule = require("webpack/lib/NormalModule");
var OrderUndefinedError = require("./OrderUndefinedError");
var loaderUtils = require("loader-utils");
var validateOptions = require('schema-utils');
Expand Down Expand Up @@ -186,15 +187,15 @@ ExtractTextPlugin.prototype.loader = function(options) {
ExtractTextPlugin.prototype.extract = function(options) {
if(arguments.length > 1) {
throw new Error("Breaking change: extract now only takes a single argument. Either an options " +
"object *or* the loader(s).\n" +
"Example: if your old code looked like this:\n" +
" ExtractTextPlugin.extract('style-loader', 'css-loader')\n\n" +
"You would change it to:\n" +
" ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader' })\n\n" +
"The available options are:\n" +
" use: string | object | loader[]\n" +
" fallback: string | object | loader[]\n" +
" publicPath: string\n");
"object *or* the loader(s).\n" +
"Example: if your old code looked like this:\n" +
" ExtractTextPlugin.extract('style-loader', 'css-loader')\n\n" +
"You would change it to:\n" +
" ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader' })\n\n" +
"The available options are:\n" +
" use: string | object | loader[]\n" +
" fallback: string | object | loader[]\n" +
" publicPath: string\n");
}
if(options.fallbackLoader) {
console.warn('fallbackLoader option has been deprecated - replace with "fallback"');
Expand Down Expand Up @@ -225,14 +226,15 @@ ExtractTextPlugin.prototype.extract = function(options) {
return [this.loader(options)]
.concat(before, loader)
.map(getLoaderObject);
}
};

ExtractTextPlugin.extract = ExtractTextPlugin.prototype.extract.bind(ExtractTextPlugin);

ExtractTextPlugin.prototype.apply = function(compiler) {
var options = this.options;
compiler.plugin("this-compilation", function(compilation) {
var extractCompilation = new ExtractTextPluginCompilation();
var toRemoveModules = {};
compilation.plugin("normal-module-loader", function(loaderContext, module) {
loaderContext[NS] = function(content, opt) {
if(options.disable)
Expand Down Expand Up @@ -274,21 +276,43 @@ ExtractTextPlugin.prototype.apply = function(compiler) {
if(meta && (!meta.options.id || meta.options.id === id)) {
var wasExtracted = Array.isArray(meta.content);
if(shouldExtract !== wasExtracted) {
module[NS + "/extract"] = shouldExtract; // eslint-disable-line no-path-concat
compilation.rebuildModule(module, function(err) {
var newModule = new NormalModule(
module.request,
module.userRequest,
module.rawRequest,
module.loaders,
module.resource,
module.parser
);
newModule[NS + "/extract"] = shouldExtract; // eslint-disable-line no-path-concat
// build a new module and save result to extracted compilations
compilation.buildModule(newModule, false, newModule, null, function(err) {
if(err) {
compilation.errors.push(err);
return callback();
}
meta = module[NS];
meta = newModule[NS];
// Error out if content is not an array and is not null
if(!Array.isArray(meta.content) && meta.content != null) {
err = new Error(module.identifier() + " doesn't export content");
err = new Error(newModule.identifier() + " doesn't export content");
compilation.errors.push(err);
return callback();
}
if(meta.content)
extractCompilation.addResultToChunk(module.identifier(), meta.content, module, extractedChunk);
if(meta.content) {
var ident = module.identifier();
extractCompilation.addResultToChunk(ident, meta.content, module, extractedChunk);
// remove generated result from chunk
if(toRemoveModules[ident]) {
toRemoveModules[ident].chunks.push(chunk)
} else {
toRemoveModules[ident] = {
module: newModule,
moduleToRemove: module,
chunks: [chunk]
};
}

}
callback();
});
} else {
Expand Down Expand Up @@ -318,6 +342,32 @@ ExtractTextPlugin.prototype.apply = function(compiler) {
callback();
}.bind(this));
}.bind(this));
compilation.plugin("optimize-module-ids", function(modules){
modules.forEach(function (module) {
var data = toRemoveModules[module.identifier()];
if (data) {
var id = module.id;
var newModule = new NormalModule(
module.request,
module.userRequest,
module.rawRequest,
module.loaders,
module.resource,
module.parser
);
newModule.id = id;
newModule._source = data.module._source;
data.chunks.forEach(function (chunk) {
chunk.removeModule(data.moduleToRemove);
var deps = data.moduleToRemove.dependencies;
deps.forEach(d => {
chunk.removeModule(d.module);
});
chunk.addModule(newModule);
});
}
});
});
compilation.plugin("additional-assets", function(callback) {
extractedChunks.forEach(function(extractedChunk) {
if(extractedChunk.modules.length) {
Expand Down
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -32,6 +32,7 @@
"mocha": "^3.2.0",
"mocha-lcov-reporter": "1.3.0",
"raw-loader": "^0.5.1",
"rimraf": "^2.6.1",
"should": "^11.1.2",
"standard-version": "^4.1.0",
"style-loader": "^0.18.2",
Expand Down
62 changes: 33 additions & 29 deletions test/TestCases.test.js
Expand Up @@ -3,6 +3,7 @@ var vm = require("vm");
var path = require("path");
var webpack = require("webpack");
var should = require("should");
var rimraf = require('rimraf');
var ExtractTextPlugin = require("../");

var cases = process.env.CASES ? process.env.CASES.split(",") : fs.readdirSync(path.join(__dirname, "cases"));
Expand All @@ -12,36 +13,39 @@ describe("TestCases", function() {
it(testCase, function(done) {
var testDirectory = path.join(__dirname, "cases", testCase);
var outputDirectory = path.join(__dirname, "js", testCase);
var options = { entry: { test: "./index.js" } };
var configFile = path.join(testDirectory, "webpack.config.js");
if(fs.existsSync(configFile))
options = require(configFile);
options.context = testDirectory;
if(!options.module) options.module = {};
if(!options.module.loaders) options.module.loaders = [
{ test: /\.txt$/, loader: ExtractTextPlugin.extract("raw-loader") }
];
if(!options.output) options.output = { filename: "[name].js" };
if(!options.output.path) options.output.path = outputDirectory;
if(process.env.CASES) {
console.log("\nwebpack." + testCase + ".config.js " + JSON.stringify(options, null, 2));
}
webpack(options, function(err, stats) {
if(err) return done(err);
if(stats.hasErrors()) return done(new Error(stats.toString()));
var testFile = path.join(outputDirectory, "test.js");
if(fs.existsSync(testFile))
require(testFile)(suite);
var expectedDirectory = path.join(testDirectory, "expected");
fs.readdirSync(expectedDirectory).forEach(function(file) {
var filePath = path.join(expectedDirectory, file);
var actualPath = path.join(outputDirectory, file);
readFileOrEmpty(actualPath).should.be.eql(
readFileOrEmpty(filePath),
file + " should be correct");
function test() {
var options = { entry: { test: "./index.js" } };
var configFile = path.join(testDirectory, "webpack.config.js");
if (fs.existsSync(configFile))
options = require(configFile);
options.context = testDirectory;
if (!options.module) options.module = {};
if (!options.module.loaders) options.module.loaders = [
{ test: /\.txt$/, loader: ExtractTextPlugin.extract("raw-loader") }
];
if (!options.output) options.output = { filename: "[name].js" };
if (!options.output.path) options.output.path = outputDirectory;
if (process.env.CASES) {
console.log("\nwebpack." + testCase + ".config.js " + JSON.stringify(options, null, 2));
}
webpack(options, function (err, stats) {
if (err) return done(err);
if (stats.hasErrors()) return done(new Error(stats.toString()));
var testFile = path.join(outputDirectory, "test.js");
if (fs.existsSync(testFile))
require(testFile)(suite);
var expectedDirectory = path.join(testDirectory, "expected");
fs.readdirSync(expectedDirectory).forEach(function (file) {
var filePath = path.join(expectedDirectory, file);
var actualPath = path.join(outputDirectory, file);
readFileOrEmpty(actualPath).should.be.eql(
readFileOrEmpty(filePath),
file + " should be correct");
});
done();
});
done();
});
}
rimraf(outputDirectory, test);
});
});
});
Expand Down
3 changes: 3 additions & 0 deletions test/cases/multiple-entries-all-async/default-styles.css
@@ -0,0 +1,3 @@
body {
background: red;
}
2 changes: 2 additions & 0 deletions test/cases/multiple-entries-all-async/entries/contact.js
@@ -0,0 +1,2 @@
require('../router');
require('../routes/contact');
2 changes: 2 additions & 0 deletions test/cases/multiple-entries-all-async/entries/homepage.js
@@ -0,0 +1,2 @@
require('../router');
require('../routes/homepage');
22 changes: 22 additions & 0 deletions test/cases/multiple-entries-all-async/expected/0.js
@@ -0,0 +1,22 @@
webpackJsonp([0],{

/***/ 2:
/***/ (function(module, exports, __webpack_require__) {

__webpack_require__(7);

modules.export = function() {
return 'Route Homepage';
};


/***/ }),

/***/ 7:
/***/ (function(module, exports) {

// removed by extract-text-webpack-plugin

/***/ })

});
22 changes: 22 additions & 0 deletions test/cases/multiple-entries-all-async/expected/1.js
@@ -0,0 +1,22 @@
webpackJsonp([1],{

/***/ 1:
/***/ (function(module, exports, __webpack_require__) {

__webpack_require__(6);

modules.export = function() {
return 'Route Contact';
};


/***/ }),

/***/ 6:
/***/ (function(module, exports) {

// removed by extract-text-webpack-plugin

/***/ })

});
9 changes: 9 additions & 0 deletions test/cases/multiple-entries-all-async/expected/contact.css
@@ -0,0 +1,9 @@
body {
background: red;
}
.contact {
color: black;
}
.homepage {
color: black;
}
9 changes: 9 additions & 0 deletions test/cases/multiple-entries-all-async/expected/homepage.css
@@ -0,0 +1,9 @@
body {
background: red;
}
.contact {
color: black;
}
.homepage {
color: black;
}
6 changes: 6 additions & 0 deletions test/cases/multiple-entries-all-async/router.js
@@ -0,0 +1,6 @@
require('./default-styles.css');
module.export = function (route) {
return import(/* webpackChunkName: "route-[request]" */ './routes/' + route + 'index.js').then(function (route) {
return route;
});
};
5 changes: 5 additions & 0 deletions test/cases/multiple-entries-all-async/routes/contact/index.js
@@ -0,0 +1,5 @@
require('./styles.css');

modules.export = function() {
return 'Route Contact';
};
@@ -0,0 +1,3 @@
.contact {
color: black;
}
@@ -0,0 +1,5 @@
require('./styles.css');

modules.export = function() {
return 'Route Homepage';
};
@@ -0,0 +1,3 @@
.homepage {
color: black;
}
23 changes: 23 additions & 0 deletions test/cases/multiple-entries-all-async/webpack.config.js
@@ -0,0 +1,23 @@
var ExtractTextPlugin = require("../../../");
module.exports = {
entry: {
'homepage': "./entries/homepage.js",
'contact': "./entries/contact.js"
},
module: {
loaders: [
{ test: /\.css$/, use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: { loader: "css-loader", options: {
sourceMap: false
} }
}) }
]
},
plugins: [
new ExtractTextPlugin({
filename: '[name].css',
allChunks: true
})
]
};
3 changes: 3 additions & 0 deletions test/cases/multiple-entries-async/default-styles.css
@@ -0,0 +1,3 @@
body {
background: red;
}
2 changes: 2 additions & 0 deletions test/cases/multiple-entries-async/entries/contact.js
@@ -0,0 +1,2 @@
require('../router');
require('../routes/contact');
2 changes: 2 additions & 0 deletions test/cases/multiple-entries-async/entries/homepage.js
@@ -0,0 +1,2 @@
require('../router');
require('../routes/homepage');