Skip to content

Commit

Permalink
fix(purgecss-webpack-plugin): add sourcemap support #409
Browse files Browse the repository at this point in the history
BREAKING CHANGE: drop webpack 4 support
  • Loading branch information
Ffloriel committed Feb 23, 2022
1 parent b2b92fc commit b3f73ed
Show file tree
Hide file tree
Showing 11 changed files with 117 additions and 57 deletions.
7 changes: 3 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion packages/postcss-purgecss/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
*
* @public
*/
export interface UserDefinedOptions extends Omit<PurgeCSSUserDefinedOptions, "css"> {
export interface UserDefinedOptions extends Omit<PurgeCSSUserDefinedOptions,"content" | "css"> {
content?: PurgeCSSUserDefinedOptions['content'];
contentFunction?: (sourceFile: string) => Array<string | RawContent>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const PATHS = {

module.exports = {
mode: "development",
devtool: false,
entry: "./src/index.js",
context: path.resolve(__dirname),
optimization: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const PATHS = {

module.exports = {
mode: "development",
devtool: false,
entry: {
bundle: "./src/index.js",
legacy: "./src/legacy.js",
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const PATHS = {

module.exports = {
mode: "development",
devtool: "source-map",
optimization: {
splitChunks: {
cacheGroups: {
Expand Down
9 changes: 4 additions & 5 deletions packages/purgecss-webpack-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,18 @@
},
"dependencies": {
"purgecss": "^4.1.3",
"webpack": "*",
"webpack-sources": "^3.2.0"
"webpack": ">=5.0.0"
},
"bugs": {
"url": "https://github.com/FullHuman/purgecss/issues"
},
"devDependencies": {
"@types/webpack-sources": "^3.2.0",
"css-loader": "^6.2.0",
"mini-css-extract-plugin": "^2.1.0"
"css-loader": "^6.6.0",
"mini-css-extract-plugin": "^2.5.0"
},
"peerDependencies": {
"webpack": "*"
"webpack": ">=5.0.0"
},
"publishConfig": {
"access": "public",
Expand Down
138 changes: 95 additions & 43 deletions packages/purgecss-webpack-plugin/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import * as fs from "fs";
import * as path from "path";
import { PurgeCSS, defaultOptions } from "purgecss";
import { Compilation, Compiler } from "webpack";
import { ConcatSource } from "webpack-sources";
import {
PurgeCSS,
defaultOptions,
ResultPurge,
UserDefinedOptions as PurgeCSSUserDefinedOptions,
} from "purgecss";
import { Compilation, Compiler, sources } from "webpack";
import { PurgedStats, UserDefinedOptions } from "./types";

export * from "./types";
Expand All @@ -12,6 +16,7 @@ const pluginName = "PurgeCSS";

/**
* Get the filename without ?hash
*
* @param fileName - file name
*/
function getFormattedFilename(fileName: string): string {
Expand All @@ -23,6 +28,7 @@ function getFormattedFilename(fileName: string): string {

/**
* Returns true if the filename is of types of one of the specified extensions
*
* @param filename - file name
* @param extensions - extensions
*/
Expand All @@ -31,6 +37,78 @@ function isFileOfTypes(filename: string, extensions: string[]): boolean {
return extensions.includes(extension);
}

function getPurgeCSSOptions(
pluginOptions: UserDefinedOptions,
filesToSearch: string[],
asset: sources.Source,
fileName: string,
sourceMap: boolean
): PurgeCSSUserDefinedOptions {
const options = {
...defaultOptions,
...pluginOptions,
content: filesToSearch,
css: [
{
raw: asset.source().toString(),
},
],
};

if (typeof options.safelist === "function") {
options.safelist = options.safelist();
}

if (typeof options.blocklist === "function") {
options.blocklist = options.blocklist();
}

return {
content: options.content,
css: options.css,
defaultExtractor: options.defaultExtractor,
extractors: options.extractors,
fontFace: options.fontFace,
keyframes: options.keyframes,
output: options.output,
rejected: options.rejected,
variables: options.variables,
safelist: options.safelist,
blocklist: options.blocklist,
sourceMap: sourceMap ? { inline: false, to: fileName } : false,
};
}

/**
* Create the Source instance result of PurgeCSS
*
* @param name - asset name
* @param asset - webpack asset
* @param purgeResult - result of PurgeCSS purge method
* @param sourceMap - wether sourceMap is enabled
* @returns the new Source
*/
function createSource(
name: string,
asset: sources.Source,
purgeResult: ResultPurge,
sourceMap: boolean
): sources.Source {
if (!sourceMap || !purgeResult.sourceMap) {
return new sources.RawSource(purgeResult.css);
}
const { source, map } = asset.sourceAndMap();

return new sources.SourceMapSource(
purgeResult.css,
name,
purgeResult.sourceMap,
source.toString(),
map,
false
);
}

/**
* @public
*/
Expand Down Expand Up @@ -80,60 +158,34 @@ export class PurgeCSSPlugin {
return this.options.only.some((only) => name.includes(only));
}

return Array.isArray(chunk.files)
? chunk.files.includes(name)
: chunk.files.has(name);
return chunk.files.has(name);
});

for (const [name, asset] of assetsToPurge) {
const filesToSearch = entryPaths.filter(
(v) => !styleExtensions.some((ext) => v.endsWith(ext))
);

// Compile through Purgecss and attach to output.
// This loses sourcemaps should there be any!
const options = {
...defaultOptions,
...this.options,
content: filesToSearch,
css: [
{
raw: asset.source().toString(),
},
],
};

if (typeof options.safelist === "function") {
options.safelist
options.safelist = options.safelist();
}

if (typeof options.blocklist === "function") {
options.blocklist = options.blocklist();
}
const sourceMapEnabled = !!compilation.compiler.options.devtool;
const purgeCSSOptions = getPurgeCSSOptions(
this.options,
filesToSearch,
asset,
name,
sourceMapEnabled
);

const purgecss = await new PurgeCSS().purge({
content: options.content,
css: options.css,
defaultExtractor: options.defaultExtractor,
extractors: options.extractors,
fontFace: options.fontFace,
keyframes: options.keyframes,
output: options.output,
rejected: options.rejected,
variables: options.variables,
safelist: options.safelist,
blocklist: options.blocklist,
});
const purgecss = await new PurgeCSS().purge(purgeCSSOptions);
const purged = purgecss[0];

if (purged.rejected) {
this.purgedStats[name] = purged.rejected;
}

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
compilation.updateAsset(name, new ConcatSource(purged.css));
compilation.updateAsset(
name,
createSource(name, asset, purged, sourceMapEnabled)
);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/purgecss-webpack-plugin/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export type PurgedStats = {
/**
* @public
*/
export type UserDefinedOptions = Omit<PurgeCSSUserDefinedOptions, "css" | "content" | "safelist" | "blocklist"> & {
export type UserDefinedOptions = Omit<PurgeCSSUserDefinedOptions, "css" | "content" | "safelist" | "blocklist" | "sourceMap"> & {
paths: string[] | PathFunction;
moduleExtensions?: string[];
verbose?: boolean;
Expand Down
5 changes: 4 additions & 1 deletion packages/purgecss/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,10 @@ class PurgeCSS {
if (this.options.keyframes) this.removeUnusedKeyframes();
if (this.options.variables) this.removeUnusedCSSVariables();

const postCSSResult = root.toResult({ map: this.options.sourceMap });
const postCSSResult = root.toResult({
map: this.options.sourceMap,
to: typeof this.options.sourceMap === 'object' ? this.options.sourceMap.to : undefined
});
const result: ResultPurge = {
css: postCSSResult.toString(),
file: typeof option === "string" ? option : option.name,
Expand Down
4 changes: 2 additions & 2 deletions packages/purgecss/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ export interface UserDefinedOptions {
/** {@inheritDoc Options.rejectedCss} */
rejectedCss?: boolean;
/** {@inheritDoc Options.sourceMap } */
sourceMap?: boolean | postcss.SourceMapOptions
sourceMap?: boolean | postcss.SourceMapOptions & { to?: string }
/** {@inheritDoc Options.stdin} */
stdin?: boolean;
/** {@inheritDoc Options.stdout} */
Expand Down Expand Up @@ -229,7 +229,7 @@ export interface Options {
rejected: boolean;
rejectedCss: boolean;
/** {@inheritDoc postcss#SourceMapOptions} */
sourceMap: boolean | postcss.SourceMapOptions
sourceMap: boolean | postcss.SourceMapOptions & { to?: string }
stdin: boolean;
stdout: boolean;
variables: boolean;
Expand Down

0 comments on commit b3f73ed

Please sign in to comment.