Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Major feature: match() #163

Merged
merged 18 commits into from
Jun 10, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 34 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ All blocks, like `babel6`, `postcss` and so on, live in their own small packages
```js
const {
createConfig,
match,
webpack,

// Feature blocks
Expand All @@ -61,16 +62,21 @@ const {
sourceMaps
} = require('webpack-blocks')
const autoprefixer = require('autoprefixer')
const path = require('path')

module.exports = createConfig([
entryPoint('./src/main.js'),
setOutput('./build/bundle.js'),
css(),
babel(),
postcss([
autoprefixer({ browsers: ['last 2 versions'] })
match('*.css', { exclude: path.resolve('node_modules') }, [
css(),
postcss([
autoprefixer({ browsers: ['last 2 versions'] })
])
]),
match(['*.gif', '*.jpg', '*.jpeg', '*.png', '*.webp'], [
file()
]),
file('image'),
defineConstants({
'process.env.NODE_ENV': process.env.NODE_ENV
}),
Expand Down Expand Up @@ -98,7 +104,9 @@ const { css } = require('webpack-blocks')

module.exports = createConfig([
...
css.modules()
match('*.css', { exclude: path.resolve('node_modules') }, [
css.modules()
]
])
```

Expand All @@ -110,21 +118,25 @@ module.exports = createConfig([
myCssLoader([ './styles' ])
])

function myCssLoader (include) {
function myCssLoader () {
return (context, { merge }) => merge({
module: {
rules: [
{
test: context.fileType('text/css'),
use: [ 'style-loader', 'my-css-loader' ],
include
}
Object.assign(
{
test: /\.css$/,
use: [ 'style-loader', 'my-css-loader' ]
},
context.match // carries `test`, `exclude` & `include` as set by `match()`
)
]
}
})
}
```

If we use `myCssLoader` in `match()` then `context.match` will be populated with whatever we set in `match()`. Otherwise there is still the `test: /\.css$/` fallback, so our block will work without `match()` as well.

Check out the [sample app](./test-app) to see a webpack config in action or read [how to create your own blocks](./docs/BLOCK-CREATION.md).


Expand Down Expand Up @@ -206,15 +218,17 @@ Take the `babel6` webpack block for instance:
* @param {RegExp|Function|string} [options.exclude] Directories to exclude.
* @return {Function}
*/
function babel (options) {
const { exclude = /\/node_modules\// } = options || {}

return (context, util) => util.addLoader({
// we use a `MIME type => RegExp` abstraction here in order to have consistent regexs
test: context.fileType('application/javascript'),
exclude: Array.isArray(exclude) ? exclude : [ exclude ],
use: [ 'babel-loader?cacheDirectory' ]
})
function babel (options = { cacheDirectory: true }) {
return (context, util) => util.addLoader(
Object.assign({
// we use a `MIME type => RegExp` abstraction here in order to have consistent regexs
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [
{ loader: 'babel-loader', options }
]
}, context.match)
)
}
```

Expand Down
61 changes: 31 additions & 30 deletions docs/BLOCK-CREATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,32 +29,28 @@ Take the `babel6` webpack block for instance:
* @param {RegExp|Function|string} [options.exclude] Directories to exclude.
* @return {Function}
*/
function babel (options) {
const { exclude = /\/node_modules\// } = options || {}

function babel (options = { cacheDirectory: true }) {
return (context, util) => prevConfig => ({
...prevConfig,
module: {
...prevConfig.module,
rules: prevConfig.module.rules.concat([
{
Object.assign({
// we use a `MIME type => RegExp` abstraction here in order to have consistent regexs
test: context.fileType('application/javascript'),
exclude: Array.isArray(exclude) ? exclude : [ exclude ],
use: [{
loader: 'babel-loader',
options: {
cacheDirectory: true,
}
}]
}
// setting `test` & `exclude` defaults here, in case there is no `context.match` data
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [
{ loader: 'babel-loader', options }
]
}, context.match) // carries `test`, `exclude` & `include` as set by `match()`
])
}
})
}
```

Thus it is also super easy to unit test and generic enough to share it with the world.
Thus it is also pretty easy to unit test and generic enough to share it with the world.


## Block Utilities
Expand All @@ -67,10 +63,12 @@ Returns an update function that adds the given loader definition to a webpack co

```js
function sampleBlock () {
return (context, { addLoader }) => addLoader({
test: context.fileType('text/css'),
use: [ 'style-loader', 'css-loader' ]
})
return (context, { addLoader }) => addLoader(
Object.assign({
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
}, context.match)
)
}
```

Expand Down Expand Up @@ -107,24 +105,27 @@ The context object is a metadata object that is passed to every block. It is mea

Initially it will contain the `fileType` mapping and a `webpack` instance. If you are using [hooks](#hooks) you might want to put custom metadata into the context and use it in the `post` hook.

### context.fileType

*Deprecated. This feature will be removed soon. Use `match()` and `context.match` instead.*

The `context.fileType` is a mapping from MIME type (`application/javascript`, `text/css`, ...) to a regular expression used for matching filenames. You can find the default file types and the extensions they match [here](https://github.com/andywer/webpack-blocks/blob/master/packages/core/lib/defaultFileTypes.js).

The `context.webpack` property is the webpack instance, so you do not have to `require('webpack')` in your blocks.
### context.match

### Adding custom file types
This is where the file matching patterns reside you set by using `match()` in the configuration.

To add a new `fileType` you can use the `fileType.add(mimeType: string, regex: RegExp)` function. See its usage in the `typescript` block:
If the block is used within a `match()` then `context.match` will contain:

```js
function preHook (context) {
const registeredTypes = context.fileType.all()
if (!('application/x-typescript' in registeredTypes)) {
context.fileType.add('application/x-typescript', /\.(ts|tsx)$/)
}
}
```
* `test`: Which files to match, usually a regex or an array of regexs. Always present.
* `exclude`: Condition(s) which paths not to match. Might not be present.
* `include`: Condition(s) to override `exclude`. Might not be present.

Every block using MIME types that are not already defined in `core/lib/defaultFileTypes.js` needs to have a similar pre [hook](#Hooks) to register its custom types. If it is a rather common file type feel free to open a pull request for adding it to the `defaultFileTypes` as well.
If the block is not used within a `match()` then `context.match` will be undefined.

### context.webpack

The `context.webpack` property is the webpack instance, so you do not have to `require('webpack')` in your blocks.


## Hooks
Expand Down
12 changes: 7 additions & 5 deletions docs/TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,21 +42,23 @@ It is also quite simple to write one. Here is a short example:

```js
import test from 'ava'
import { createConfig } from 'webpack-blocks'
import { createConfig, match } from 'webpack-blocks'
import myBlock from '../my-block'

test('my block adds the loader with custom exclude', t => {
test('my block works with match()', t => {
const output = createConfig([
myBlock({ exclude: /node_modules/ })
match('*.myext', { exclude: /node_modules/ }, [
myBlock()
])
])

t.deepEqual(output, {
module: {
rules: [
{
test: /.myext/,
test: /^.*\.myext/,
exclude: /node_modules/,
use: 'my-fancy-loader'
use: [ 'my-fancy-loader' ]
}
]
}
Expand Down
9 changes: 9 additions & 0 deletions packages/assets/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# @webpack-blocks/assets - Changelog

## Next release

- Breaking API change. Use `match()` instead of passing a file type option.

## 1.0.0-alpha

- Initial release
54 changes: 24 additions & 30 deletions packages/assets/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,64 +9,58 @@ This is the `assets` block providing configuration for the style loader, file lo
## Usage

```js
const { createConfig } = require('@webpack-blocks/webpack')
const { createConfig, match } = require('@webpack-blocks/webpack')
const { css, file, url } = require('@webpack-blocks/assets')

module.exports = createConfig([
css(),
file('application/font'), // will copy font files and link to them
url('image', { limit: 10000 }) // will load images up to 10KB as data URL
css(), // or use `match()` to apply it to other files than *.css
match(['*.eot', '*.ttf', '*.woff', '*.woff2'], [
file() // will copy font files to build directory and link to them
]),
match(['*.gif', '*.jpg', '*.jpeg', '*.png', '*.svg', '*.webp'], [
url({ limit: 10000 }) // will load images up to 10KB as data URL
])
])
```

In order to use CSS modules:

```js
const { createConfig } = require('@webpack-blocks/webpack')
const { createConfig, match } = require('@webpack-blocks/webpack')
const { css } = require('@webpack-blocks/assets')

module.exports = createConfig([
css.modules({
exclude: [ /node_modules/ ],
localIdentName: '[name]--[local]--[hash:base64:5]'
})
match('*.css', { exclude: path.resolve('node_modules') }, [
css.modules({
localIdentName: '[name]--[local]--[hash:base64:5]'
})
])
])
```


## Generic options
## API

#### exclude *(optional)*
Regular expression, string or function describing which files/directories to exclude from the babeling.
### css(options: ?object)

#### include *(optional)*
Regular expression, string or function used to white-list which files/directories should be babeled. By default `exclude` is set only.
Will match `*.css` by default if not used with `match()`. You can pass all [css-loader options](https://github.com/webpack-contrib/css-loader).

### css.modules(options: ?object)

## Specific usage
Will match `*.css` by default if not used with `match()`. You can pass all [css-loader options](https://github.com/webpack-contrib/css-loader).

### css(fileType: ?string, options: ?object)

`fileType` defaults to `'text/css'` which matches `*.css`. You can pass all [css-loader options](https://github.com/webpack-contrib/css-loader).

### css.modules(fileType: ?string, options: ?object)

`fileType` defaults to `'text/css'` which matches `*.css`. You can pass all [css-loader options](https://github.com/webpack-contrib/css-loader).

The difference to `css()` is that it sets the following options:
The difference to `css()` is that it sets the following css-loader options:
* `modules: true`
* `importLoaders` defaults to `1`
* `localIdentName` defaults to `'[name]--[local]--[hash:base64:5]'` in development and `'[hash:base64:10]'` in production

### file(fileType: string, options: ?object)
### file(options: ?object)

The file type is supposed to be a MIME type or MIME media type like `text/css`, `image`, `image/jpeg`, ... as defined by the [default file types](https://github.com/andywer/webpack-blocks/blob/master/packages/core/lib/defaultFileTypes.js) or other blocks.
You can pass all [file-loader options](https://github.com/webpack-contrib/file-loader) as the 2nd parameter.
Must be used with `match()`. You can pass all [file-loader options](https://github.com/webpack-contrib/file-loader).

### url(fileType: string, options: ?object)
### url(options: ?object)

The file type is supposed to be a MIME type or MIME media type like `text/css`, `image`, `image/jpeg`, ... as defined by the [default file types](https://github.com/andywer/webpack-blocks/blob/master/packages/core/lib/defaultFileTypes.js) or other blocks.
You can pass all [url-loader options](https://github.com/webpack-contrib/url-loader). We strongly recommend setting a `limit` to prevent huge files to be encoded as a data URL.
Must be used with `match()`. You can pass all [url-loader options](https://github.com/webpack-contrib/url-loader). We strongly recommend setting a `limit` to prevent huge files to be encoded as a data URL.


## Webpack blocks
Expand Down
Loading