diff --git a/CHANGELOG.md b/CHANGELOG.md index 33b2c44..05933b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,35 @@ ## purifycss-webpack +0.7.0 / 2017-05-16 +================== + + * Breaking - Push **purify-css** as a peer dependency. #108 + +0.6.2 / 2017-05-08 +================== + + * Docs - Add **glob-all** example. #105 + +0.6.1 / 2017-04-14 +================== + + * Docs - Fix CSS Modules example (prefix has to be lowercase to work). + +0.6.0 / 2017-04-07 +================== + + * Feature - Allow asset names to contain `?`. Example: `style.css?218aa9358a709a5a0a12`. #94 + +0.5.0 / 2017-03-02 +================== + + * Feature - Add strict validation against `paths`. #88 + +0.4.3 / 2017-03-01 +================== + + * Bug fix - Fix chunk file match dependency on [name]. #86 + 0.4.2 / 2017-01-28 ================== diff --git a/README.md b/README.md index 9227908..078fd07 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ +# UNMAINTAINED + +Please use: https://github.com/FullHuman/purgecss-webpack-plugin + +--- [![npm][npm]][npm-url] [![deps][deps]][deps-url] [![test][test]][test-url] @@ -24,7 +29,7 @@ Without any CSS file being emitted as an asset, this plugin will do nothing. You

Install

```bash -npm i -D purifycss-webpack +npm i -D purifycss-webpack purify-css ```

Usage

@@ -64,6 +69,19 @@ module.exports = { And, that's it! Your scripts and view files will be scanned for classes, and those that are unused will be stripped off your CSS - aka. "purified". +In order to use this plugin to look into multiple paths you will need to: + +1. npm install --save glob-all +2. Add `const glob = require('glob-all');` at the top of your webpack config +3. Then you can pass your paths to an array, like so: + +```javascript +paths: glob.sync([ + path.join(__dirname, '.php'), + path.join(__dirname, 'partials/.php') +]), +``` + > You can pass an object (` -> []`) to `paths` if you want to control the behavior per entry.

Options

@@ -81,6 +99,44 @@ This plugin, unlike the original PurifyCSS plugin, provides special features, su > The plugin does **not** emit sourcemaps even if you enable `sourceMap` option on loaders! +

Usage with CSS Modules

+ +PurifyCSS doesn't support classes that have been namespaced with CSS Modules. However, by adding a static string to `css-loader`'s `localIdentName`, you can effectively whitelist these namespaced classes. + +In this example, `purify` will be our whitelisted string. **Note:** Make sure this string doesn't occur in any of your other CSS class names. Keep in mind that whatever you choose will end up in your application at runtime - try to keep it short! + +```javascript +module.exports = { + module: { + rules: [ + { + test: /\.css$/, + loader: ExtractTextPlugin.extract({ + fallback: 'style-loader', + use: [ + { + loader: 'css-loader', + options: { + localIdentName: 'purify_[hash:base64:5]', + modules: true + } + } + ] + }) + } + ] + }, + plugins: [ + ..., + new PurifyCSSPlugin({ + purifyOptions: { + whitelist: ['*purify*'] + } + }) + ] +}; +``` +

Maintainers

diff --git a/examples/README.md b/examples/README.md index 38f104a..daa6189 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,5 +1,6 @@ 1. `npm install` at project root 2. `npm run build` 3. `cd examples` -4. `npm run build` -5. Examine `./build` +4. `npm install` +5. `npm run build` +6. Examine `./build` diff --git a/examples/webpack.parts.js b/examples/webpack.parts.js index f905fd6..4933b1f 100644 --- a/examples/webpack.parts.js +++ b/examples/webpack.parts.js @@ -16,7 +16,7 @@ exports.extractCSS = function extractCSS(paths) { ] }, plugins: [ - new ExtractTextPlugin('[name].css') + new ExtractTextPlugin('[name].css?[hash]') ] }; }; diff --git a/package.json b/package.json index bca5c90..cee2a3e 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,15 @@ { "name": "purifycss-webpack", - "version": "0.4.2", + "version": "0.7.0", "description": "PurifyCSS for webpack", "main": "./dist", "scripts": { - "build": "babel src -d dist", + "build": "rimraf dist && babel src -d dist", "build:watch": "npm-watch", "test:all": "npm run test:coverage && npm run test:lint", - "test": "jest --", - "test:coverage": "jest --coverage --", - "test:watch": "jest --watch --", + "test": "jest", + "test:coverage": "jest --coverage", + "test:watch": "jest --watch", "test:lint": "eslint . --ext .js --ignore-path .gitignore --cache", "preversion": "npm run test:all && npm run build && git commit --allow-empty -am \"Update dist\"", "postinstall": "node lib/post_install.js" @@ -39,17 +39,16 @@ ] }, "author": "Kenny Tran, Matthew Rourke, Phoebe Li, Kevin \"Ingwie Phoenix\" Ingwersen", - "license": "ISC", + "license": "MIT", "bugs": { "url": "https://github.com/webpack-contrib/purifycss-webpack/issues" }, "homepage": "https://github.com/webpack-contrib/purifycss-webpack", "peerDependencies": { - "webpack": "^1.9 || ^2.2.0 || ^2.1.0-beta || ^2.2.0-rc" + "purify-css": ">= 1.0.0 < 2.0.0" }, "dependencies": { "ajv": "^4.11.2", - "purify-css": "^1.1.9", "webpack-sources": "^0.1.4" }, "devDependencies": { @@ -67,7 +66,9 @@ "eslint-plugin-react": "^6.9.0", "git-prepush-hook": "^1.0.1", "jest": "^18.1.0", - "npm-watch": "^0.1.8" + "npm-watch": "^0.1.8", + "purify-css": "^1.2.2", + "rimraf": "^2.6.1" }, "pre-push": [ "build", @@ -75,7 +76,9 @@ ], "watch": { "build": { - "patterns": ["src"], + "patterns": [ + "src" + ], "extensions": "js", "quiet": false } diff --git a/src/index.js b/src/index.js index f4e6977..3acdaaf 100644 --- a/src/index.js +++ b/src/index.js @@ -1,3 +1,4 @@ +import fs from 'fs'; import purify from 'purify-css'; import { ConcatSource } from 'webpack-sources'; import * as parse from './parse'; @@ -22,6 +23,10 @@ module.exports = function PurifyPlugin(options) { compiler.plugin('this-compilation', (compilation) => { const entryPaths = parse.entryPaths(options.paths); + parse.flatten(entryPaths).forEach((p) => { + if (!fs.existsSync(p)) throw new Error(`Path ${p} does not exist.`); + }); + // Output debug information through a callback pattern // to avoid unnecessary processing const output = options.verbose ? @@ -31,11 +36,11 @@ module.exports = function PurifyPlugin(options) { compilation.plugin('additional-assets', (cb) => { // Go through chunks and purify as configured compilation.chunks.forEach( - ({ name: chunkName, modules }) => { + ({ name: chunkName, files, modules }) => { const assetsToPurify = search.assets( compilation.assets, options.styleExtensions ).filter( - asset => asset.name.indexOf(chunkName) >= 0 + asset => files.indexOf(asset.name) >= 0 ); output(() => [ diff --git a/src/parse.js b/src/parse.js index 58ffee1..0797085 100644 --- a/src/parse.js +++ b/src/parse.js @@ -9,6 +9,12 @@ function parseEntryPaths(paths) { return ret; } +function flattenEntryPaths(paths) { + return Array.isArray(paths) ? + paths : + Object.keys(paths).reduce((acc, val) => [...acc, ...paths[val]], []); +} + function parseEntries(paths, chunkName) { if (Array.isArray(paths)) { return paths; @@ -25,5 +31,6 @@ function parseEntries(paths, chunkName) { module.exports = { entryPaths: parseEntryPaths, + flatten: flattenEntryPaths, entries: parseEntries }; diff --git a/src/parse.test.js b/src/parse.test.js index 721df94..1b75d7e 100644 --- a/src/parse.test.js +++ b/src/parse.test.js @@ -19,6 +19,20 @@ describe('Parse entry paths', function () { }); }); +describe('Flatten entry paths', function () { + it('returns an array as itself', function () { + const a = ['a', 'b', 'c']; + + assert.deepEqual(parse.flatten(a), a); + }); + + it('returns an object of arrays as one flat array', function () { + const o = { a: ['a', 'b'], b: ['c', 'd'] }; + + assert.deepEqual(parse.flatten(o), ['a', 'b', 'c', 'd']); + }); +}); + describe('Parse entries', function () { it('returns paths if there is no chunk name', function () { const paths = ['a', 'b', 'c']; diff --git a/src/search.js b/src/search.js index cab74f4..80d33e8 100644 --- a/src/search.js +++ b/src/search.js @@ -5,7 +5,13 @@ function searchAssets( extensions = [] ) { return Object.keys(assets).map( - name => extensions.indexOf(path.extname(name)) >= 0 && { name, asset: assets[name] } + name => ( + extensions.indexOf( + path.extname( + name.indexOf('?') >= 0 ? name.split('?').slice(0, -1).join('') : name + ) + ) >= 0 && { name, asset: assets[name] } + ) ).filter(a => a); } diff --git a/src/search.test.js b/src/search.test.js index 512b7d7..a542091 100644 --- a/src/search.test.js +++ b/src/search.test.js @@ -16,6 +16,17 @@ describe('Search assets', function () { assert.deepEqual(search.assets(modules, extensions), matches); }); + + it('returns matches if they have query', function () { + const modules = { + 'foobar.txt?123': {}, + 'barbar.css': {} + }; + const extensions = ['.txt']; + const matches = [{ name: 'foobar.txt?123', asset: {} }]; + + assert.deepEqual(search.assets(modules, extensions), matches); + }); }); describe('Search files', function () {