diff --git a/.babelrc b/.babelrc
deleted file mode 100644
index f7fd45b..0000000
--- a/.babelrc
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "presets": [
- "es2015"
- ],
- "plugins": [
- "syntax-object-rest-spread",
- "transform-object-rest-spread"
- ]
-}
diff --git a/.editorconfig b/.editorconfig
deleted file mode 100644
index 52494a4..0000000
--- a/.editorconfig
+++ /dev/null
@@ -1,9 +0,0 @@
-# editorconfig.org
-
-[*]
-indent_style = space
-indent_size = 2
-end_of_line = lf
-charset = utf-8
-trim_trailing_whitespace = true
-insert_final_newline = true
diff --git a/.eslintrc.js b/.eslintrc.js
deleted file mode 100644
index 2c370f0..0000000
--- a/.eslintrc.js
+++ /dev/null
@@ -1,16 +0,0 @@
-module.exports = {
- "extends": "airbnb",
- "env": {
- "browser": true,
- "node": true,
- "mocha": true
- },
- "rules": {
- "prefer-arrow-callback": 0, // mocha tests (recommendation)
- "func-names": 0, // mocha tests (recommendation)
- "comma-dangle": ["error", "never"], // personal preference
- "no-param-reassign": 0, // the plugin needs this (webpack design :( )
- "no-use-before-define": 0, // personal preference
- "no-console": 0 // allow logging
- }
-};
diff --git a/.gitignore b/.gitignore
index 9d256f2..bf0d423 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,33 @@
-node_modules/
-build/
-dist/
-coverage/
+#floobits
+.floobits
+.flooignore
+
+# Logs
+logs
*.log
-.eslintcache
+# Runtime data
+pids
+*.pid
+*.seed
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (http://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directory
+# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
+node_modules
+
+example
\ No newline at end of file
diff --git a/.npmignore b/.npmignore
deleted file mode 100644
index 552f221..0000000
--- a/.npmignore
+++ /dev/null
@@ -1,2 +0,0 @@
-node_modules/
-*.log
diff --git a/.travis.yml b/.travis.yml
index 33fce7f..d2f3209 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,11 +1 @@
-language: node_js
-node_js:
- - "4"
- - "5"
- - "6"
-script:
- - (cd examples && npm i)
- - npm run build
- - npm run test:all
-after_success:
- - bash <(curl -s https://codecov.io/bash)
+language: node_js
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
deleted file mode 100644
index 05933b9..0000000
--- a/CHANGELOG.md
+++ /dev/null
@@ -1,90 +0,0 @@
-## 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
-==================
-
- * Feature - Show nicer errors if there are extra fields.
-
-0.4.1 / 2017-01-28
-==================
-
- * Bug fix - If an entry name does not match while processing, skip it. #72
-
-0.4.0 / 2017-01-27
-==================
-
- * Bug fix - Support `Install
-
-```bash
-npm i -D purifycss-webpack purify-css
+# Installation
```
-
-Usage
-
-Configure as follows:
-
-```javascript
-const path = require('path');
-const glob = require('glob');
-const ExtractTextPlugin = require('extract-text-webpack-plugin');
-const PurifyCSSPlugin = require('purifycss-webpack');
-
-module.exports = {
- entry: {...},
- output: {...},
- module: {
- rules: [
- {
- test: /\.css$/,
- loader: ExtractTextPlugin.extract({
- fallbackLoader: 'style-loader',
- loader: 'css-loader'
- })
- }
- ]
- },
- plugins: [
- new ExtractTextPlugin('[name].[contenthash].css'),
- // Make sure this is after ExtractTextPlugin!
- new PurifyCSSPlugin({
- // Give paths to parse for rules. These should be absolute!
- paths: glob.sync(path.join(__dirname, 'app/*.html')),
- })
- ]
-};
+npm install purifycss-loader
```
-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:
+# Usage
+``` javascript
+var PurifyCssPlugin = require('purifycss-loader/PurifyCssPlugin');
-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')
-]),
-```
+var webpackConfig = {
+ // ...
-> You can pass an object (`Options
-
-This plugin, unlike the original PurifyCSS plugin, provides special features, such as scanning the dependency files. You can configure using the following fields:
-
-| Property | Description
-|---------------------|------------
-| `styleExtensions` | An array of file extensions for determining used classes within style files. Defaults to `['.css']`.
-| `moduleExtensions` | An array of file extensions for determining used classes within `node_modules`. Defaults to `[]`, but `['.html']` can be useful here.
-| `minimize` | Enable CSS minification. Alias to `purifyOptions.minify`. Disabled by default.
-| `paths` | An array of absolute paths or a path to traverse. This also accepts an object (`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
- }
- }
- ]
- })
- }
- ]
+ loaders: [{
+ test: /\.css$/, loader: "style-loader!css-loader!purifycss-loader"
+ }]
},
+
plugins: [
- ...,
- new PurifyCSSPlugin({
- purifyOptions: {
- whitelist: ['*purify*']
- }
- })
+ new PurifyCssPlugin(__dirname, '/index.html')
]
-};
+}
```
-Maintainers
-
-
-
-
-
-
-[npm]: https://img.shields.io/npm/v/purifycss-webpack.svg
-[npm-url]: https://npmjs.com/package/purifycss-webpack
-
-[deps]: https://david-dm.org/webpack-contrib/purifycss-webpack.svg
-[deps-url]: https://david-dm.org/webpack-contrib/purifycss-webpack
-
-[chat]: https://img.shields.io/badge/gitter-webpack%2Fwebpack-brightgreen.svg
-[chat-url]: https://gitter.im/webpack/webpack
-
-[test]: https://secure.travis-ci.org/webpack-contrib/purifycss-webpack.svg
-[test-url]: http://travis-ci.org/webpack-contrib/purifycss-webpack
-
-[cover]: https://codecov.io/gh/webpack-contrib/purifycss-webpack/branch/master/graph/badge.svg
-[cover-url]: https://codecov.io/gh/webpack-contrib/purifycss-webpack
-
-[quality]: https://www.bithound.io/github/webpack-contrib/purifycss-webpack/badges/score.svg
-[quality-url]: https://www.bithound.io/github/webpack-contrib/purifycss-webpack
+# API
+Pass in the filepath to the root html for us to detect classes there. PurifyCSS will look at all your bundles on its own.
diff --git a/examples/README.md b/examples/README.md
deleted file mode 100644
index daa6189..0000000
--- a/examples/README.md
+++ /dev/null
@@ -1,6 +0,0 @@
-1. `npm install` at project root
-2. `npm run build`
-3. `cd examples`
-4. `npm install`
-5. `npm run build`
-6. Examine `./build`
diff --git a/examples/another/component.js b/examples/another/component.js
deleted file mode 100644
index 859f06b..0000000
--- a/examples/another/component.js
+++ /dev/null
@@ -1,8 +0,0 @@
-export default function () {
- const element = document.createElement('h1');
-
- element.className = 'pure-table';
- element.innerHTML = 'Hello world Again';
-
- return element;
-}
diff --git a/examples/another/index.js b/examples/another/index.js
deleted file mode 100644
index 960ad6b..0000000
--- a/examples/another/index.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import 'purecss';
-import './main.css';
-import component from './component';
-
-document.body.appendChild(component());
diff --git a/examples/another/main.css b/examples/another/main.css
deleted file mode 100644
index b1645d6..0000000
--- a/examples/another/main.css
+++ /dev/null
@@ -1,7 +0,0 @@
-body {
- background: cornsilk;
-}
-
-body div {
- background-color: deepskyblue;
-}
diff --git a/examples/app/component.js b/examples/app/component.js
deleted file mode 100644
index 54d7e41..0000000
--- a/examples/app/component.js
+++ /dev/null
@@ -1,8 +0,0 @@
-export default function () {
- const element = document.createElement('h1');
-
- element.className = 'pure-button';
- element.innerHTML = 'Hello world';
-
- return element;
-}
diff --git a/examples/app/index.js b/examples/app/index.js
deleted file mode 100644
index 960ad6b..0000000
--- a/examples/app/index.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import 'purecss';
-import './main.css';
-import component from './component';
-
-document.body.appendChild(component());
diff --git a/examples/app/main.css b/examples/app/main.css
deleted file mode 100644
index b1645d6..0000000
--- a/examples/app/main.css
+++ /dev/null
@@ -1,7 +0,0 @@
-body {
- background: cornsilk;
-}
-
-body div {
- background-color: deepskyblue;
-}
diff --git a/examples/package.json b/examples/package.json
deleted file mode 100644
index 5469eec..0000000
--- a/examples/package.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "name": "examples",
- "scripts": {
- "build": "webpack"
- },
- "dependencies": {
- "css-loader": "^0.26.1",
- "extract-text-webpack-plugin": "^2.0.0-beta.5",
- "glob": "^7.1.1",
- "purecss": "^0.6.2",
- "style-loader": "^0.13.1",
- "webpack": "^2.2.0-rc.3",
- "webpack-merge": "^2.4.0"
- }
-}
diff --git a/examples/webpack.config.js b/examples/webpack.config.js
deleted file mode 100644
index aacb91d..0000000
--- a/examples/webpack.config.js
+++ /dev/null
@@ -1,52 +0,0 @@
-const path = require('path');
-const merge = require('webpack-merge');
-const glob = require('glob');
-
-const parts = require('./webpack.parts');
-
-const PATHS = {
- app: path.join(__dirname, 'app'),
- another: path.join(__dirname, 'another'),
- build: path.join(__dirname, 'build')
-};
-
-module.exports = [
- merge(
- {
- entry: {
- app: PATHS.app
- },
- output: {
- path: path.join(PATHS.build, 'first'),
- filename: '[name].js'
- }
- },
- parts.extractCSS(),
- parts.purifyCSS({
- verbose: true,
- minimize: true,
- paths: glob.sync(`${PATHS.app}/*`),
- styleExtensions: ['.css']
- })
- ),
- merge(
- {
- entry: {
- first: PATHS.app,
- second: PATHS.another
- },
- output: {
- path: path.join(PATHS.build, 'second'),
- filename: '[name].js'
- }
- },
- parts.extractCSS(),
- parts.purifyCSS({
- paths: {
- first: glob.sync(`${PATHS.app}/*`),
- second: glob.sync(`${PATHS.another}/*`)
- },
- styleExtensions: ['.css']
- })
- )
-];
diff --git a/examples/webpack.parts.js b/examples/webpack.parts.js
deleted file mode 100644
index 4933b1f..0000000
--- a/examples/webpack.parts.js
+++ /dev/null
@@ -1,30 +0,0 @@
-const ExtractTextPlugin = require('extract-text-webpack-plugin');
-const PurifyCSSPlugin = require('../');
-
-exports.extractCSS = function extractCSS(paths) {
- return {
- module: {
- rules: [
- {
- test: /\.css$/,
- include: paths,
- loader: ExtractTextPlugin.extract({
- fallbackLoader: 'style-loader',
- loader: 'css-loader?sourceMap'
- })
- }
- ]
- },
- plugins: [
- new ExtractTextPlugin('[name].css?[hash]')
- ]
- };
-};
-
-exports.purifyCSS = function purifyCSS(options) {
- return {
- plugins: [
- new PurifyCSSPlugin(options)
- ]
- };
-};
diff --git a/lib/post_install.js b/lib/post_install.js
deleted file mode 100644
index 8d6218c..0000000
--- a/lib/post_install.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// adapted based on rackt/history (MIT)
-// Node 4+
-var execSync = require('child_process').execSync;
-var stat = require('fs').stat;
-
-function exec(command) {
- execSync(command, {
- stdio: [0, 1, 2]
- });
-}
-
-stat('dist', function(error, stat) {
- // Skip building on Travis
- if (process.env.TRAVIS) {
- return;
- }
-
- if (error || !stat.isDirectory()) {
- exec('npm i babel-cli babel-preset-es2015 babel-plugin-syntax-object-rest-spread babel-plugin-transform-object-rest-spread');
- exec('npm run build');
- }
-});
diff --git a/loader.js b/loader.js
new file mode 100644
index 0000000..2ff4afe
--- /dev/null
+++ b/loader.js
@@ -0,0 +1,11 @@
+var purify = require('purify-css');
+
+module.exports = function(input){
+ if(typeof this._compilation._purifycss_content === 'undefined'){
+ return input;
+ }
+
+ var content = this._compilation._purifycss_content;
+
+ return purify(content, input);
+};
diff --git a/package.json b/package.json
index cee2a3e..32d1b16 100644
--- a/package.json
+++ b/package.json
@@ -1,22 +1,14 @@
{
- "name": "purifycss-webpack",
- "version": "0.7.0",
- "description": "PurifyCSS for webpack",
- "main": "./dist",
+ "name": "purifycss-loader",
+ "version": "1.0.0",
+ "description": "PurifyCSS plugin for webpack",
+ "main": "loader.js",
"scripts": {
- "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: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"
+ "test": "./node_modules/.bin/nodeunit test/plugin.js"
},
"repository": {
"type": "git",
- "url": "https://github.com/webpack-contrib/purifycss-webpack.git"
+ "url": "https://github.com/purifycss/purifycss-webpack-plugin.git"
},
"keywords": [
"webpack",
@@ -24,63 +16,21 @@
"plugin",
"purify"
],
- "files": [
- "dist",
- "lib"
- ],
- "jest": {
- "collectCoverage": true,
- "collectCoverageFrom": "src/**/*.js",
- "moduleFileExtensions": [
- "js"
- ],
- "moduleDirectories": [
- "node_modules"
- ]
- },
- "author": "Kenny Tran, Matthew Rourke, Phoebe Li, Kevin \"Ingwie Phoenix\" Ingwersen",
- "license": "MIT",
+ "author": "Kenny Tran, Matthew Rourke, Phoebe Li",
+ "license": "ISC",
"bugs": {
- "url": "https://github.com/webpack-contrib/purifycss-webpack/issues"
- },
- "homepage": "https://github.com/webpack-contrib/purifycss-webpack",
- "peerDependencies": {
- "purify-css": ">= 1.0.0 < 2.0.0"
+ "url": "https://github.com/purifycss/purifycss-webpack-plugin/issues"
},
+ "homepage": "https://github.com/purifycss/purifycss-webpack-plugin",
"dependencies": {
- "ajv": "^4.11.2",
- "webpack-sources": "^0.1.4"
+ "css-loader": "^0.14.2",
+ "purify-css": "^1.0.0",
+ "style-loader": "^0.12.3"
},
"devDependencies": {
- "babel-cli": "^6.18.0",
- "babel-core": "^6.21.0",
- "babel-eslint": "^7.1.1",
- "babel-jest": "^18.0.0",
- "babel-plugin-syntax-object-rest-spread": "^6.13.0",
- "babel-plugin-transform-object-rest-spread": "^6.20.2",
- "babel-preset-es2015": "^6.18.0",
- "eslint": "^3.13.1",
- "eslint-config-airbnb": "^14.0.0",
- "eslint-plugin-import": "^2.2.0",
- "eslint-plugin-jsx-a11y": "^3.0.2",
- "eslint-plugin-react": "^6.9.0",
- "git-prepush-hook": "^1.0.1",
- "jest": "^18.1.0",
- "npm-watch": "^0.1.8",
- "purify-css": "^1.2.2",
- "rimraf": "^2.6.1"
- },
- "pre-push": [
- "build",
- "test:all"
- ],
- "watch": {
- "build": {
- "patterns": [
- "src"
- ],
- "extensions": "js",
- "quiet": false
- }
+ "purify-css": "^1.0.0",
+ "string": "^3.1.1",
+ "nodeunit": "^0.9",
+ "webpack": "^1.0"
}
}
diff --git a/src/index.js b/src/index.js
deleted file mode 100644
index 3acdaaf..0000000
--- a/src/index.js
+++ /dev/null
@@ -1,85 +0,0 @@
-import fs from 'fs';
-import purify from 'purify-css';
-import { ConcatSource } from 'webpack-sources';
-import * as parse from './parse';
-import * as search from './search';
-import validateOptions from './validate-options';
-import schema from './schema';
-
-module.exports = function PurifyPlugin(options) {
- return {
- apply(compiler) {
- const validation = validateOptions(
- schema({
- entry: compiler.options.entry
- }),
- options
- );
-
- if (!validation.isValid) {
- throw new Error(validation.error);
- }
-
- 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 ?
- messageCb => console.info(...messageCb()) :
- () => {};
-
- compilation.plugin('additional-assets', (cb) => {
- // Go through chunks and purify as configured
- compilation.chunks.forEach(
- ({ name: chunkName, files, modules }) => {
- const assetsToPurify = search.assets(
- compilation.assets, options.styleExtensions
- ).filter(
- asset => files.indexOf(asset.name) >= 0
- );
-
- output(() => [
- 'Assets to purify:',
- assetsToPurify.map(({ name }) => name).join(', ')
- ]);
-
- assetsToPurify.forEach(({ name, asset }) => {
- const filesToSearch = parse.entries(entryPaths, chunkName).concat(
- search.files(
- modules, options.moduleExtensions || [], file => file.resource
- )
- );
-
- output(() => [
- 'Files to search for used rules:',
- filesToSearch.join(', ')
- ]);
-
- // Compile through Purify and attach to output.
- // This loses sourcemaps should there be any!
- compilation.assets[name] = new ConcatSource(
- purify(
- filesToSearch,
- asset.source(),
- {
- info: options.verbose,
- minify: options.minimize,
- ...options.purifyOptions
- }
- )
- );
- });
- }
- );
-
- cb();
- });
- });
- }
- };
-};
diff --git a/src/parse.js b/src/parse.js
deleted file mode 100644
index 0797085..0000000
--- a/src/parse.js
+++ /dev/null
@@ -1,36 +0,0 @@
-function parseEntryPaths(paths) {
- const ret = paths || [];
-
- // Convert possible string to an array
- if (typeof ret === 'string') {
- return [ret];
- }
-
- 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;
- }
-
- if (!(chunkName in paths)) {
- return [];
- }
-
- const ret = paths[chunkName];
-
- return Array.isArray(ret) ? ret : [ret];
-}
-
-module.exports = {
- entryPaths: parseEntryPaths,
- flatten: flattenEntryPaths,
- entries: parseEntries
-};
diff --git a/src/parse.test.js b/src/parse.test.js
deleted file mode 100644
index 1b75d7e..0000000
--- a/src/parse.test.js
+++ /dev/null
@@ -1,83 +0,0 @@
-const assert = require('assert');
-const parse = require('./parse');
-
-describe('Parse entry paths', function () {
- it('returns an empty array by default', function () {
- assert.deepEqual(parse.entryPaths(), []);
- });
-
- it('returns an object as itself', function () {
- const o = { a: ['a', 'b', 'c'] };
-
- assert.deepEqual(parse.entryPaths(o), o);
- });
-
- it('puts a string inside an array', function () {
- const str = 'foobar';
-
- assert.deepEqual(parse.entryPaths(str), [str]);
- });
-});
-
-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'];
-
- assert.deepEqual(parse.entries(paths), paths);
- });
-
- it('returns paths if paths are an array already', function () {
- const paths = ['a', 'b', 'c'];
-
- assert.deepEqual(parse.entries(paths, 'foobar'), paths);
- });
-
- it('returns chunk paths', function () {
- const entryPaths = ['a', 'b', 'c'];
- const paths = {
- foobar: entryPaths
- };
-
- assert.deepEqual(parse.entries(paths, 'foobar'), entryPaths);
- });
-
- it('returns chunk path wrapped in an array', function () {
- const entryPaths = 'a';
- const paths = {
- foobar: entryPaths
- };
-
- assert.deepEqual(parse.entries(paths, 'foobar'), [entryPaths]);
- });
-
- it('returns an empty array if failed to find entry', function () {
- const paths = {
- foobar: 'a'
- };
-
- assert.deepEqual(parse.entries(paths, 'barbar'), []);
- });
-
- it('returns an empty array if failed to find entry with multiple paths', function () {
- const paths = {
- foobar: 'a',
- barbar: 'b'
- };
-
- assert.deepEqual(parse.entries(paths, 'foofoo'), []);
- });
-});
diff --git a/src/schema.js b/src/schema.js
deleted file mode 100644
index cce104d..0000000
--- a/src/schema.js
+++ /dev/null
@@ -1,68 +0,0 @@
-const schema = ({ entry } = {}) => ({
- $schema: 'http://json-schema.org/draft-04/schema#',
- additionalProperties: false,
- type: 'object',
- properties: {
- styleExtensions: {
- type: 'array',
- items: {
- type: 'string'
- },
- default: ['.css']
- },
- minimize: {
- type: 'boolean'
- },
- moduleExtensions: {
- type: 'array',
- items: {
- type: 'string'
- }
- },
- paths: parsePaths(entry),
- purifyOptions: {
- type: 'object',
- properties: {}
- },
- verbose: {
- type: 'boolean'
- }
- },
- required: [
- 'paths'
- ]
-});
-
-function parsePaths(entry) {
- const ret = {
- type: ['array', 'object']
- };
-
- if (entry instanceof Object) {
- ret.additionalProperties = false;
- ret.properties = generateProperties(entry);
- } else {
- ret.items = {
- type: 'string'
- };
- }
-
- return ret;
-}
-
-function generateProperties(entry) {
- const ret = {};
-
- Object.keys(entry).forEach((e) => {
- ret[e] = {
- type: ['array', 'string'],
- items: {
- type: 'string'
- }
- };
- });
-
- return ret;
-}
-
-export default schema;
diff --git a/src/schema.test.js b/src/schema.test.js
deleted file mode 100644
index 8d01808..0000000
--- a/src/schema.test.js
+++ /dev/null
@@ -1,21 +0,0 @@
-const assert = require('assert');
-const schema = require('./schema').default;
-
-describe('Schema', function () {
- it('converts an object entry to validation', function () {
- const entry = {
- a: 'foo'
- };
- const result = schema({ entry });
- const expected = {
- a: {
- type: ['array', 'string'],
- items: {
- type: 'string'
- }
- }
- };
-
- assert.deepEqual(result.properties.paths.properties, expected);
- });
-});
diff --git a/src/search.js b/src/search.js
deleted file mode 100644
index 80d33e8..0000000
--- a/src/search.js
+++ /dev/null
@@ -1,37 +0,0 @@
-const path = require('path');
-
-function searchAssets(
- assets = [],
- extensions = []
-) {
- return Object.keys(assets).map(
- name => (
- extensions.indexOf(
- path.extname(
- name.indexOf('?') >= 0 ? name.split('?').slice(0, -1).join('') : name
- )
- ) >= 0 && { name, asset: assets[name] }
- )
- ).filter(a => a);
-}
-
-function searchFiles(
- modules = {},
- extensions = [],
- getter = a => a
-) {
- return Object.keys(modules).map((name) => {
- const file = getter(modules[name]);
-
- if (!file) {
- return null;
- }
-
- return extensions.indexOf(path.extname(file)) >= 0 && file;
- }).filter(a => a);
-}
-
-module.exports = {
- assets: searchAssets,
- files: searchFiles
-};
diff --git a/src/search.test.js b/src/search.test.js
deleted file mode 100644
index a542091..0000000
--- a/src/search.test.js
+++ /dev/null
@@ -1,89 +0,0 @@
-const assert = require('assert');
-const search = require('./search');
-
-describe('Search assets', function () {
- it('returns nothing if nothing is passed', function () {
- assert.deepEqual(search.assets(), []);
- });
-
- it('returns matches based on a pattern', function () {
- const modules = {
- 'foobar.txt': {},
- 'barbar.css': {}
- };
- const extensions = ['.txt'];
- const matches = [{ name: 'foobar.txt', asset: {} }];
-
- 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 () {
- it('returns nothing if nothing is passed', function () {
- assert.deepEqual(search.files(), []);
- });
-
- it('returns matches based on extension', function () {
- const modules = ['foobar.txt', 'barbar.css'];
- const extensions = ['.txt'];
- const matches = ['foobar.txt'];
-
- assert.deepEqual(search.files(modules, extensions), matches);
- });
-
- it('does not fail with missing modules', function () {
- const modules = ['foobar.txt', '', 'barbar.css'];
- const extensions = ['.txt'];
- const matches = ['foobar.txt'];
-
- assert.deepEqual(search.files(modules, extensions), matches);
- });
-
- it('returns matches based on extension with a customized getter', function () {
- const modules = {
- foobar: {
- resource: 'foobar.txt'
- },
- barbar: {
- resource: 'barbar.css'
- }
- };
- const extensions = ['.txt'];
- const matches = ['foobar.txt'];
-
- assert.deepEqual(
- search.files(modules, extensions, file => file.resource),
- matches
- );
- });
-
- it('does not fail with missing modules when a getter fails', function () {
- const modules = {
- foobar: {
- resource: 'foobar.txt'
- },
- demo: {},
- barbar: {
- resource: 'barbar.css'
- }
- };
- const extensions = ['.txt'];
- const matches = ['foobar.txt'];
-
- assert.deepEqual(
- search.files(modules, extensions, file => file.resource),
- matches
- );
- });
-});
diff --git a/src/validate-options.js b/src/validate-options.js
deleted file mode 100644
index c06ec45..0000000
--- a/src/validate-options.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import Ajv from 'ajv';
-
-function validateOptions(schema, data) {
- const ajv = new Ajv({
- useDefaults: true, // This mutates the original data with defaults!
- errorDataPath: 'property'
- });
- const isValid = ajv.validate(schema, data);
-
- return {
- isValid,
- error: ajv.errors && ajv.errorsText()
- };
-}
-
-export default validateOptions;
diff --git a/src/validate-options.test.js b/src/validate-options.test.js
deleted file mode 100644
index fbae580..0000000
--- a/src/validate-options.test.js
+++ /dev/null
@@ -1,63 +0,0 @@
-const assert = require('assert');
-const validateOptions = require('./validate-options').default;
-const schema = require('./schema').default;
-
-describe('Validate options', function () {
- it('fails without a schema and data', function () {
- assert.throws(
- () => {
- validateOptions();
- },
- Error
- );
- });
-
- it('fails with empty data', function () {
- const result = validateOptions(schema());
-
- assert.ok(!result.isValid);
- assert.ok(result.error);
- });
-
- it('does not fail if paths are provided', function () {
- const result = validateOptions(schema(), { paths: ['./foo'] });
-
- assert.ok(result.isValid);
- assert.ok(!result.error);
- });
-
- it('does not allow arbitrary properties', function () {
- const result = validateOptions(schema(), { paths: ['./foo'], foobar: ['./foo'] });
-
- assert.ok(!result.isValid);
- assert.ok(result.error);
- });
-
- it('styleExtensions have defaults', function () {
- const paths = ['./foo'];
- const data = { paths };
-
- // Currently this mutates data with defaults due to ajv design. It
- // might be a good idea to change that behavior, though.
- const result = validateOptions(schema(), data);
-
- assert.deepEqual(data, { paths, styleExtensions: ['.css'] });
- assert.ok(!result.error);
- });
-
- it('fails without matching path keys', function () {
- const data = {
- paths: {
- a: './foo'
- }
- };
-
- const result = validateOptions(schema({
- entry: {
- b: './bar'
- }
- }), data);
-
- assert.ok(result.error);
- });
-});
diff --git a/test/fixtures/content.js b/test/fixtures/content.js
new file mode 100644
index 0000000..3c463bb
--- /dev/null
+++ b/test/fixtures/content.js
@@ -0,0 +1,3 @@
+module.exports = "It works from content.js.";
+
+console.log('body');
diff --git a/test/fixtures/entry.js b/test/fixtures/entry.js
new file mode 100644
index 0000000..a9eb919
--- /dev/null
+++ b/test/fixtures/entry.js
@@ -0,0 +1,3 @@
+require("!style!css!./style.css");
+require("!style!css!./style2.css");
+document.write(require("./content.js"));
\ No newline at end of file
diff --git a/test/fixtures/index.html b/test/fixtures/index.html
new file mode 100644
index 0000000..49c6b5a
--- /dev/null
+++ b/test/fixtures/index.html
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/fixtures/style.css b/test/fixtures/style.css
new file mode 100644
index 0000000..ace4a01
--- /dev/null
+++ b/test/fixtures/style.css
@@ -0,0 +1,12 @@
+body {
+ background: yellow;
+}
+p{
+ background: green;
+}
+video {
+ background: white;
+}
+span{
+ background: blue;
+}
\ No newline at end of file
diff --git a/test/fixtures/style2.css b/test/fixtures/style2.css
new file mode 100644
index 0000000..4138bce
--- /dev/null
+++ b/test/fixtures/style2.css
@@ -0,0 +1,19 @@
+body {
+ background: red;
+}
+
+div{
+ color:purple;
+}
+
+h1 {
+ margin: 5px;
+}
+
+h2 {
+ padding: 20em;
+}
+
+button {
+ background-color: black;
+}
\ No newline at end of file
diff --git a/test/output/bundle.js b/test/output/bundle.js
new file mode 100644
index 0000000..88f8191
--- /dev/null
+++ b/test/output/bundle.js
@@ -0,0 +1,408 @@
+/******/ (function(modules) { // webpackBootstrap
+/******/ // The module cache
+/******/ var installedModules = {};
+
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+
+/******/ // Check if module is in cache
+/******/ if(installedModules[moduleId])
+/******/ return installedModules[moduleId].exports;
+
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = installedModules[moduleId] = {
+/******/ exports: {},
+/******/ id: moduleId,
+/******/ loaded: false
+/******/ };
+
+/******/ // Execute the module function
+/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+
+/******/ // Flag the module as loaded
+/******/ module.loaded = true;
+
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+
+
+/******/ // expose the modules object (__webpack_modules__)
+/******/ __webpack_require__.m = modules;
+
+/******/ // expose the module cache
+/******/ __webpack_require__.c = installedModules;
+
+/******/ // __webpack_public_path__
+/******/ __webpack_require__.p = "";
+
+/******/ // Load entry module and return exports
+/******/ return __webpack_require__(0);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/***/ function(module, exports, __webpack_require__) {
+
+ __webpack_require__(1);
+ __webpack_require__(5);
+ document.write(__webpack_require__(7));
+
+/***/ },
+/* 1 */
+/***/ function(module, exports, __webpack_require__) {
+
+ // style-loader: Adds some css to the DOM by adding a tag
+
+ // load the styles
+ var content = __webpack_require__(2);
+ if(typeof content === 'string') content = [[module.id, content, '']];
+ // add the styles to the DOM
+ var update = __webpack_require__(4)(content, {});
+ if(content.locals) module.exports = content.locals;
+ // Hot Module Replacement
+ if(false) {
+ // When the styles change, update the tags
+ if(!content.locals) {
+ module.hot.accept("!!./../../node_modules/css-loader/index.js!./style.css", function() {
+ var newContent = require("!!./../../node_modules/css-loader/index.js!./style.css");
+ if(typeof newContent === 'string') newContent = [[module.id, newContent, '']];
+ update(newContent);
+ });
+ }
+ // When the module is disposed, remove the tags
+ module.hot.dispose(function() { update(); });
+ }
+
+/***/ },
+/* 2 */
+/***/ function(module, exports, __webpack_require__) {
+
+ exports = module.exports = __webpack_require__(3)();
+ exports.push([module.id, "body {\n background: yellow;\n}\np{\n background: green;\n}\n", ""]);
+
+/***/ },
+/* 3 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Tobias Koppers @sokra
+ */
+ // css base code, injected by the css-loader
+ module.exports = function() {
+ var list = [];
+
+ // return the list of modules as css string
+ list.toString = function toString() {
+ var result = [];
+ for(var i = 0; i < this.length; i++) {
+ var item = this[i];
+ if(item[2]) {
+ result.push("@media " + item[2] + "{" + item[1] + "}");
+ } else {
+ result.push(item[1]);
+ }
+ }
+ return result.join("");
+ };
+
+ // import a list of modules into the list
+ list.i = function(modules, mediaQuery) {
+ if(typeof modules === "string")
+ modules = [[null, modules, ""]];
+ var alreadyImportedModules = {};
+ for(var i = 0; i < this.length; i++) {
+ var id = this[i][0];
+ if(typeof id === "number")
+ alreadyImportedModules[id] = true;
+ }
+ for(i = 0; i < modules.length; i++) {
+ var item = modules[i];
+ // skip already imported module
+ // this implementation is not 100% perfect for weird media query combinations
+ // when a module is imported multiple times with different media queries.
+ // I hope this will never occur (Hey this way we have smaller bundles)
+ if(typeof item[0] !== "number" || !alreadyImportedModules[item[0]]) {
+ if(mediaQuery && !item[2]) {
+ item[2] = mediaQuery;
+ } else if(mediaQuery) {
+ item[2] = "(" + item[2] + ") and (" + mediaQuery + ")";
+ }
+ list.push(item);
+ }
+ }
+ };
+ return list;
+ };
+
+
+/***/ },
+/* 4 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Tobias Koppers @sokra
+ */
+ var stylesInDom = {},
+ memoize = function(fn) {
+ var memo;
+ return function () {
+ if (typeof memo === "undefined") memo = fn.apply(this, arguments);
+ return memo;
+ };
+ },
+ isOldIE = memoize(function() {
+ return /msie [6-9]\b/.test(window.navigator.userAgent.toLowerCase());
+ }),
+ getHeadElement = memoize(function () {
+ return document.head || document.getElementsByTagName("head")[0];
+ }),
+ singletonElement = null,
+ singletonCounter = 0;
+
+ module.exports = function(list, options) {
+ if(false) {
+ if(typeof document !== "object") throw new Error("The style-loader cannot be used in a non-browser environment");
+ }
+
+ options = options || {};
+ // Force single-tag solution on IE6-9, which has a hard limit on the # of
+ // tags it will allow on a page
+ if (typeof options.singleton === "undefined") options.singleton = isOldIE();
+
+ var styles = listToStyles(list);
+ addStylesToDom(styles, options);
+
+ return function update(newList) {
+ var mayRemove = [];
+ for(var i = 0; i < styles.length; i++) {
+ var item = styles[i];
+ var domStyle = stylesInDom[item.id];
+ domStyle.refs--;
+ mayRemove.push(domStyle);
+ }
+ if(newList) {
+ var newStyles = listToStyles(newList);
+ addStylesToDom(newStyles, options);
+ }
+ for(var i = 0; i < mayRemove.length; i++) {
+ var domStyle = mayRemove[i];
+ if(domStyle.refs === 0) {
+ for(var j = 0; j < domStyle.parts.length; j++)
+ domStyle.parts[j]();
+ delete stylesInDom[domStyle.id];
+ }
+ }
+ };
+ }
+
+ function addStylesToDom(styles, options) {
+ for(var i = 0; i < styles.length; i++) {
+ var item = styles[i];
+ var domStyle = stylesInDom[item.id];
+ if(domStyle) {
+ domStyle.refs++;
+ for(var j = 0; j < domStyle.parts.length; j++) {
+ domStyle.parts[j](item.parts[j]);
+ }
+ for(; j < item.parts.length; j++) {
+ domStyle.parts.push(addStyle(item.parts[j], options));
+ }
+ } else {
+ var parts = [];
+ for(var j = 0; j < item.parts.length; j++) {
+ parts.push(addStyle(item.parts[j], options));
+ }
+ stylesInDom[item.id] = {id: item.id, refs: 1, parts: parts};
+ }
+ }
+ }
+
+ function listToStyles(list) {
+ var styles = [];
+ var newStyles = {};
+ for(var i = 0; i < list.length; i++) {
+ var item = list[i];
+ var id = item[0];
+ var css = item[1];
+ var media = item[2];
+ var sourceMap = item[3];
+ var part = {css: css, media: media, sourceMap: sourceMap};
+ if(!newStyles[id])
+ styles.push(newStyles[id] = {id: id, parts: [part]});
+ else
+ newStyles[id].parts.push(part);
+ }
+ return styles;
+ }
+
+ function createStyleElement() {
+ var styleElement = document.createElement("style");
+ var head = getHeadElement();
+ styleElement.type = "text/css";
+ head.appendChild(styleElement);
+ return styleElement;
+ }
+
+ function createLinkElement() {
+ var linkElement = document.createElement("link");
+ var head = getHeadElement();
+ linkElement.rel = "stylesheet";
+ head.appendChild(linkElement);
+ return linkElement;
+ }
+
+ function addStyle(obj, options) {
+ var styleElement, update, remove;
+
+ if (options.singleton) {
+ var styleIndex = singletonCounter++;
+ styleElement = singletonElement || (singletonElement = createStyleElement());
+ update = applyToSingletonTag.bind(null, styleElement, styleIndex, false);
+ remove = applyToSingletonTag.bind(null, styleElement, styleIndex, true);
+ } else if(obj.sourceMap &&
+ typeof URL === "function" &&
+ typeof URL.createObjectURL === "function" &&
+ typeof URL.revokeObjectURL === "function" &&
+ typeof Blob === "function" &&
+ typeof btoa === "function") {
+ styleElement = createLinkElement();
+ update = updateLink.bind(null, styleElement);
+ remove = function() {
+ styleElement.parentNode.removeChild(styleElement);
+ if(styleElement.href)
+ URL.revokeObjectURL(styleElement.href);
+ };
+ } else {
+ styleElement = createStyleElement();
+ update = applyToTag.bind(null, styleElement);
+ remove = function() {
+ styleElement.parentNode.removeChild(styleElement);
+ };
+ }
+
+ update(obj);
+
+ return function updateStyle(newObj) {
+ if(newObj) {
+ if(newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap)
+ return;
+ update(obj = newObj);
+ } else {
+ remove();
+ }
+ };
+ }
+
+ var replaceText = (function () {
+ var textStore = [];
+
+ return function (index, replacement) {
+ textStore[index] = replacement;
+ return textStore.filter(Boolean).join('\n');
+ };
+ })();
+
+ function applyToSingletonTag(styleElement, index, remove, obj) {
+ var css = remove ? "" : obj.css;
+
+ if (styleElement.styleSheet) {
+ styleElement.styleSheet.cssText = replaceText(index, css);
+ } else {
+ var cssNode = document.createTextNode(css);
+ var childNodes = styleElement.childNodes;
+ if (childNodes[index]) styleElement.removeChild(childNodes[index]);
+ if (childNodes.length) {
+ styleElement.insertBefore(cssNode, childNodes[index]);
+ } else {
+ styleElement.appendChild(cssNode);
+ }
+ }
+ }
+
+ function applyToTag(styleElement, obj) {
+ var css = obj.css;
+ var media = obj.media;
+ var sourceMap = obj.sourceMap;
+
+ if(media) {
+ styleElement.setAttribute("media", media)
+ }
+
+ if(styleElement.styleSheet) {
+ styleElement.styleSheet.cssText = css;
+ } else {
+ while(styleElement.firstChild) {
+ styleElement.removeChild(styleElement.firstChild);
+ }
+ styleElement.appendChild(document.createTextNode(css));
+ }
+ }
+
+ function updateLink(linkElement, obj) {
+ var css = obj.css;
+ var media = obj.media;
+ var sourceMap = obj.sourceMap;
+
+ if(sourceMap) {
+ // http://stackoverflow.com/a/26603875
+ css += "\n/*# sourceMappingURL=data:application/json;base64," + btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))) + " */";
+ }
+
+ var blob = new Blob([css], { type: "text/css" });
+
+ var oldSrc = linkElement.href;
+
+ linkElement.href = URL.createObjectURL(blob);
+
+ if(oldSrc)
+ URL.revokeObjectURL(oldSrc);
+ }
+
+
+/***/ },
+/* 5 */
+/***/ function(module, exports, __webpack_require__) {
+
+ // style-loader: Adds some css to the DOM by adding a tag
+
+ // load the styles
+ var content = __webpack_require__(6);
+ if(typeof content === 'string') content = [[module.id, content, '']];
+ // add the styles to the DOM
+ var update = __webpack_require__(4)(content, {});
+ if(content.locals) module.exports = content.locals;
+ // Hot Module Replacement
+ if(false) {
+ // When the styles change, update the tags
+ if(!content.locals) {
+ module.hot.accept("!!./../../node_modules/css-loader/index.js!./style2.css", function() {
+ var newContent = require("!!./../../node_modules/css-loader/index.js!./style2.css");
+ if(typeof newContent === 'string') newContent = [[module.id, newContent, '']];
+ update(newContent);
+ });
+ }
+ // When the module is disposed, remove the tags
+ module.hot.dispose(function() { update(); });
+ }
+
+/***/ },
+/* 6 */
+/***/ function(module, exports, __webpack_require__) {
+
+ exports = module.exports = __webpack_require__(3)();
+ exports.push([module.id, "body {\n background: red;\n}\n", ""]);
+
+/***/ },
+/* 7 */
+/***/ function(module, exports, __webpack_require__) {
+
+ module.exports = "It works from content.js.";
+
+ console.log('body');
+
+
+/***/ }
+/******/ ]);
\ No newline at end of file
diff --git a/test/plugin.js b/test/plugin.js
new file mode 100644
index 0000000..e9e6241
--- /dev/null
+++ b/test/plugin.js
@@ -0,0 +1,67 @@
+var fs = require('fs');
+var path = require('path');
+var webpack = require('webpack');
+var DemoPlugin = require('../');
+var S = require('string');
+
+var inputFolder = path.join(__dirname, 'fixtures');
+var inputFile = path.join(inputFolder, 'entry.js');
+var outputFolder = path.join(__dirname, 'output');
+var outputFile = path.join(outputFolder, 'bundle.js');
+
+var options = {
+ chunkModules: true,
+ exclude: [/node_modules[\\\/]/]
+};
+
+var compiler = webpack({
+ entry: inputFile,
+
+ output: {
+ path: outputFolder,
+ filename: "bundle.js"
+ },
+
+ loaders: [{
+ test: /\.css$/,
+ loader: "style!css"
+ }],
+
+ plugins: [
+ new DemoPlugin(path.join(__dirname), {
+ chunkModules: true,
+ })
+ ]
+});
+
+module.exports.tests = {
+
+ 'bundle includes all css classes': function(test) {
+ compiler.run(function(err, stats) {
+ var expected = ["body", "p"];
+ var actual = fs.readFileSync(outputFile, 'utf-8');
+
+ var allPass = expected.every(function(className) {
+ return S(actual).contains(className)
+ });
+
+ test.ok(allPass, "bundle includes all css classes");
+ test.done();
+ })
+ },
+
+ 'bundle does not include css classes not in source html/js': function(test) {
+ compiler.run(function(err, stats) {
+ var expected = ["video", "span", "div", "h1", "h2", "button"];
+ var actual = fs.readFileSync(outputFile, 'utf-8');
+
+ var allPass = expected.every(function(className) {
+ return !S(actual).contains(className)
+ });
+
+ test.ok(allPass, "bundle does not include css classes not in source html/js");
+ test.done();
+ });
+ }
+
+};
\ No newline at end of file
-
-
-
-
-
-
- Juho Vepsäläinen
-
-
-
-
- Joshua Wiens
-
-
-
-
- Kees Kluskens
-
-
-
-
- Sean Larkin
-