├── .gitattributes
├── .gitignore
├── packages
├── webpack-flow
│ ├── lib
│ │ ├── flows
│ │ │ ├── merge.js
│ │ │ ├── babel.js
│ │ │ ├── buble.js
│ │ │ ├── index.js
│ │ │ ├── env.js
│ │ │ ├── define-constants.js
│ │ │ ├── entry.js
│ │ │ ├── dest.js
│ │ │ └── uglifyjs.js
│ │ └── index.js
│ ├── package.json
│ └── test
│ │ └── index.test.js
└── css
│ ├── package.json
│ ├── test.js
│ └── index.js
├── .editorconfig
├── circle.yml
├── lerna.json
├── package.json
├── docs
├── create-a-flow.md
├── README.md
└── flows
│ ├── css.md
│ └── built-in-flows.md
├── LICENSE
├── README.md
└── yarn.lock
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | package-lock.json
3 | packages/*/yarn.lock
4 |
--------------------------------------------------------------------------------
/packages/webpack-flow/lib/flows/merge.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Usually you should add this flow after other flows
3 | */
4 | module.exports = function(obj) {
5 | return ({ config }) => config.merge(obj)
6 | }
7 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [*.md]
12 | trim_trailing_whitespace = false
--------------------------------------------------------------------------------
/circle.yml:
--------------------------------------------------------------------------------
1 | machine:
2 | node:
3 | version: 7
4 | environment:
5 | PATH: "${PATH}:${HOME}/${CIRCLE_PROJECT_REPONAME}/node_modules/.bin"
6 |
7 | dependencies:
8 | override:
9 | - yarn
10 | cache_directories:
11 | - ~/.cache/yarn
12 |
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "lerna": "2.0.0-rc.5",
3 | "packages": [
4 | "packages/*"
5 | ],
6 | "version": "independent",
7 | "commands": {
8 | "publish": {
9 | "ignore": [
10 | "*.md",
11 | "example/**",
12 | "test/**"
13 | ]
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/packages/webpack-flow/lib/flows/babel.js:
--------------------------------------------------------------------------------
1 | module.exports = function(options) {
2 | return ({ config }) => {
3 | const ruleBabel = config.module.rule('babel')
4 | ruleBabel.test(/\.jsx?$/)
5 | ruleBabel.exclude.add(/node_modules/)
6 | ruleBabel.use('babel-loader').loader('babel-loader').options(options)
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/packages/webpack-flow/lib/flows/buble.js:
--------------------------------------------------------------------------------
1 | module.exports = function(options) {
2 | return ({ config }) => {
3 | const ruleBuble = config.module.rule('buble')
4 | ruleBuble.test(/\.jsx?$/)
5 | ruleBuble.exclude.add(/node_modules/)
6 | ruleBuble.use('buble-loader').loader('buble-loader').options(options)
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/packages/webpack-flow/lib/flows/index.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | babel: require('./babel'),
3 | buble: require('./buble'),
4 | dest: require('./dest'),
5 | entry: require('./entry'),
6 | env: require('./env'),
7 | merge: require('./merge'),
8 | defineConstants: require('./define-constants'),
9 | uglifyjs: require('./uglifyjs')
10 | }
11 |
--------------------------------------------------------------------------------
/packages/webpack-flow/lib/flows/env.js:
--------------------------------------------------------------------------------
1 | module.exports = function(env, flows) {
2 | return context => {
3 | if (
4 | env === true ||
5 | (typeof env === 'string' && process.env.NODE_ENV === env) ||
6 | (typeof env === 'function' && env())
7 | ) {
8 | if (typeof flows === 'function') {
9 | flows = flows()
10 | }
11 | flows.forEach(flow => flow(context))
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/packages/webpack-flow/lib/flows/define-constants.js:
--------------------------------------------------------------------------------
1 | module.exports = function(constants) {
2 | return context => {
3 | context.config
4 | .plugin('defined-constants')
5 | .use(context.webpack.DefinePlugin, [stringifyObjValue(constants)])
6 | }
7 | }
8 |
9 | function stringifyObjValue(obj = {}) {
10 | return Object.keys(obj).reduce((res, key) => {
11 | res[key] = JSON.stringify(obj[key])
12 | return res
13 | }, {})
14 | }
15 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "name": "webpack-flow-monorepo",
4 | "version": "0.0.0",
5 | "main": "index.js",
6 | "author": "EGOIST <0x142857@gmail.com>",
7 | "license": "MIT",
8 | "devDependencies": {
9 | "eslint-config-rem": "^3.2.0",
10 | "lerna": "^2.0.0"
11 | },
12 | "scripts": {
13 | "test": "lerna bootstrap && lerna exec -- npm test"
14 | },
15 | "eslintConfig": {
16 | "extends": "rem"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/packages/webpack-flow/lib/flows/entry.js:
--------------------------------------------------------------------------------
1 | function entry(filepath, entryPoint) {
2 | entryPoint = entryPoint || 'client'
3 | return ({ config }) => {
4 | config.entry(entryPoint).add(filepath)
5 | }
6 | }
7 |
8 | entry.append = entry
9 |
10 | entry.prepend = function(filepath, entryPoint) {
11 | entryPoint = entryPoint || 'client'
12 | return ({ config }) => {
13 | config.entry(entryPoint).prepend(filepath)
14 | }
15 | }
16 |
17 | module.exports = entry
18 |
--------------------------------------------------------------------------------
/docs/create-a-flow.md:
--------------------------------------------------------------------------------
1 | # Create A Flow
2 |
3 | An example:
4 |
5 | ```js
6 | // my-flow.js
7 | module.exports = function myFlow(options) {
8 | return context => {
9 | // handle context and options
10 | }
11 | }
12 | ```
13 |
14 | Use your flow:
15 |
16 | ```js
17 | // webpack.config.js
18 | const flow = require('webpack-flow')
19 | const myFlow = require('./my-flow')
20 |
21 | module.exports = flow.createConfig([
22 | myFlow(options)
23 | ])
24 | ```
25 |
26 | ## context
27 |
28 | ### webpack
29 |
30 | Bascially the `webpack` module.
31 |
32 | ### config
33 |
34 | The [webpack-chain](https://github.com/mozilla-rpweb/webpack-chain) instance.
35 |
--------------------------------------------------------------------------------
/packages/webpack-flow/lib/index.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const webpack = require('webpack')
3 | const Config = require('webpack-chain')
4 | const builtInflows = require('./flows')
5 |
6 | function createConfigInstance(flows) {
7 | const config = new Config()
8 | const context = Object.assign({ config, webpack }, builtInflows)
9 | flows.forEach(flow => flow(context))
10 | return config
11 | }
12 |
13 | function createConfig(flows) {
14 | return createConfigInstance(flows).toConfig()
15 | }
16 |
17 | module.exports = Object.assign(
18 | {
19 | createConfigInstance,
20 | createConfig,
21 | webpack
22 | },
23 | builtInflows
24 | )
25 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # webpack-flow
2 |
3 | 👉 [To create a flow](./create-a-flow.md)
4 |
5 | ## Built-in Flows
6 |
7 | - [flow.entry](./flows/built-in-flows.md#flowentryfilepath-entrypoint)
8 | - [flow.dest](./flows/built-in-flows.md#flowdestfilepath-mergeoptions)
9 | - [flow.babel](./flows/built-in-flows.md#flowbabelloaderoptions)
10 | - [flow.buble](./flows/built-in-flows.md#flowbubleloaderoptions)
11 | - [flow.defineConstants](./flows/built-in-flows.md#flowdefineconstantsconstants)
12 | - [flow.env](./flows/built-in-flows.md#flowenvcondition-flows)
13 | - [flow.merge](./flows/built-in-flows.md#flowmergewebpackconfig)
14 |
15 | ## External Flows
16 |
17 | - [CSS](./flows/css.md)
18 |
--------------------------------------------------------------------------------
/packages/webpack-flow/lib/flows/dest.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 |
3 | module.exports = function dest(outputPath, mergeOptions) {
4 | return ({ config }) => {
5 | const parsed = path.parse(outputPath)
6 |
7 | config.output
8 | .path(parsed.dir)
9 | .filename(parsed.base)
10 | .publicPath('/')
11 | // Point sourcemap entries to original disk location
12 | .devtoolModuleFilenameTemplate(info =>
13 | path.resolve(info.absoluteResourcePath)
14 | )
15 | // Add /* filename */ comments to generated require()s in the output.
16 | .pathinfo(true)
17 |
18 | config.output.merge(mergeOptions || {})
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/packages/css/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@webpack-flow/css",
3 | "version": "1.1.0",
4 | "publishConfig": {
5 | "access": "public"
6 | },
7 | "files": [
8 | "index.js"
9 | ],
10 | "main": "index.js",
11 | "scripts": {
12 | "test": "jest --env node"
13 | },
14 | "dependencies": {
15 | "extract-text-webpack-plugin": "^2.1.0"
16 | },
17 | "devDependencies": {
18 | "babel-preset-env": "^1.5.1",
19 | "jest": "^20.0.4",
20 | "webpack": "^2.6.1",
21 | "webpack-flow": "^2.0.0"
22 | },
23 | "babel": {
24 | "presets": [
25 | [
26 | "env",
27 | {
28 | "targets": {
29 | "node": "current"
30 | }
31 | }
32 | ]
33 | ]
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/packages/webpack-flow/lib/flows/uglifyjs.js:
--------------------------------------------------------------------------------
1 | module.exports = () => {
2 | return ({ config, webpack }) => {
3 | config.plugin('uglifyjs')
4 | .use(webpack.optimize.UglifyJsPlugin, [{
5 | compress: {
6 | warnings: false,
7 | // Disabled because of an issue with Uglify breaking seemingly valid code:
8 | // https://github.com/facebookincubator/create-react-app/issues/2376
9 | // Pending further investigation:
10 | // https://github.com/mishoo/UglifyJS2/issues/2011
11 | comparisons: false,
12 | },
13 | output: {
14 | comments: false,
15 | // Turned on because emoji and regex is not minified properly using default
16 | // https://github.com/facebookincubator/create-react-app/issues/2488
17 | ascii_only: true,
18 | },
19 | sourceMap: true
20 | }])
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/packages/webpack-flow/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webpack-flow",
3 | "version": "2.0.0",
4 | "description": "Composable webpack config.",
5 | "repository": {
6 | "url": "egoist/webpack-flow",
7 | "type": "git"
8 | },
9 | "main": "lib/index.js",
10 | "files": [
11 | "lib"
12 | ],
13 | "engines": {
14 | "node": ">=6"
15 | },
16 | "scripts": {
17 | "test": "jest --env node"
18 | },
19 | "author": "egoist <0x142857@gmail.com>",
20 | "license": "MIT",
21 | "dependencies": {
22 | "webpack-chain": "^3.3.0"
23 | },
24 | "devDependencies": {
25 | "babel-jest": "^20.0.3",
26 | "babel-preset-env": "^1.5.1",
27 | "jest": "^20.0.4",
28 | "webpack": "^3.4.1"
29 | },
30 | "babel": {
31 | "presets": [
32 | [
33 | "env",
34 | {
35 | "targets": {
36 | "node": "current"
37 | }
38 | }
39 | ]
40 | ]
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/packages/css/test.js:
--------------------------------------------------------------------------------
1 | import flow from 'webpack-flow'
2 | import css from './'
3 |
4 | describe('css', () => {
5 | it('defaults', () => {
6 | const config = flow.createConfig([css()])
7 |
8 | expect(config.module.rules).toEqual([
9 | {
10 | test: /\.css$/,
11 | use: [
12 | {
13 | loader: 'style-loader',
14 | options: { sourceMap: true }
15 | },
16 | {
17 | loader: 'css-loader',
18 | options: {
19 | autoprefixer: false,
20 | sourceMap: true
21 | }
22 | }
23 | ]
24 | }
25 | ])
26 | })
27 |
28 | it('extract css', () => {
29 | const config = flow.createConfig([css({ extract: true })])
30 |
31 | expect(config.module.rules[0].use).toHaveLength(3)
32 |
33 | expect(config.plugins).toEqual([
34 | {
35 | filename: '[name].css',
36 | id: 2,
37 | options: { allChunks: true, disable: false }
38 | }
39 | ])
40 | })
41 | })
42 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) egoist <0x142857@gmail.com> (https://egoistian.com)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/docs/flows/css.md:
--------------------------------------------------------------------------------
1 | # CSS flow
2 |
3 | ## Install
4 |
5 | ```bash
6 | yarn add style-loader css-loader @webpack-flow/css --dev
7 | ```
8 |
9 | ## Usage
10 |
11 | ```js
12 | // webpack.config.js
13 | const flow = require('webpack-flow')
14 | const css = require('@webpack-flow/css')
15 |
16 | module.exports = flow.createConfig([
17 | css()
18 | ])
19 | ```
20 |
21 | ## API
22 |
23 | ### css([options])
24 |
25 | #### options
26 |
27 | ##### test
28 |
29 | Type: [`Condition`](https://webpack.js.org/configuration/module/#condition)
30 | Default: `/\.css$/`
31 |
32 | File matcher.
33 |
34 | ##### extract
35 |
36 | Type: `boolean`
37 | Default: `process.env.NODE_ENV === 'production'`
38 |
39 | Extract CSS into a single file.
40 |
41 | ##### hash
42 |
43 | Type: `boolean`
44 | Default: `process.env.NODE_ENV === 'production'`
45 |
46 | Add hash to filename for long-term caching, eg: `style.s2sd3fadf.css`.
47 |
48 | ##### sourceMap
49 |
50 | Type: `boolean`
51 | Default: `true`
52 |
53 | Enable sourceMap.
54 |
55 | ##### cssModules
56 |
57 | Type: `boolean`
58 | Default: `undefined`
59 |
60 | Enable CSS modules.
61 |
62 | ##### preLoader
63 |
64 | Type: `object` `Array