Eli Perelman
8 years ago
42 changed files with 569 additions and 2245 deletions
@ -1,60 +0,0 @@ |
|||
# Neutrino Progress Middleware |
|||
[![NPM version][npm-image]][npm-url] [![NPM downloads][npm-downloads]][npm-url] [![Join Slack][slack-image]][slack-url] |
|||
|
|||
`neutrino-middleware-progress` is Neutrino middleware for displaying a progress bar showing the progress of a build. |
|||
|
|||
## Requirements |
|||
|
|||
- Node.js v6.9+ |
|||
- Yarn or npm client |
|||
- Neutrino v5 |
|||
|
|||
## Installation |
|||
|
|||
`neutrino-middleware-progress` can be installed via the Yarn or npm clients. |
|||
|
|||
#### Yarn |
|||
|
|||
```bash |
|||
❯ yarn add neutrino-middleware-progress |
|||
``` |
|||
|
|||
#### npm |
|||
|
|||
```bash |
|||
❯ npm install --save neutrino-middleware-progress |
|||
``` |
|||
|
|||
## Usage |
|||
|
|||
`neutrino-middleware-progress` can be consumed from the Neutrino API, middleware, or presets. Require this package |
|||
and plug it into Neutrino: |
|||
|
|||
```js |
|||
const progress = require('neutrino-middleware-progress'); |
|||
|
|||
neutrino.use(progress); |
|||
``` |
|||
|
|||
## Customization |
|||
|
|||
`neutrino-middleware-progress` creates some conventions to make overriding the configuration easier once you are ready to |
|||
make changes. |
|||
|
|||
### Plugins |
|||
|
|||
The following is a list of plugins and their identifiers which can be overridden: |
|||
|
|||
- `progress`: Displays a bar showing progression of build. |
|||
|
|||
## Contributing |
|||
|
|||
This preset is part of the [neutrino-dev](https://github.com/mozilla-neutrino/neutrino-dev) repository, a monorepo |
|||
containing all resources for developing Neutrino and its core presets. Follow the |
|||
[contributing guide](../../contributing/README.md) for details. |
|||
|
|||
[npm-image]: https://img.shields.io/npm/v/neutrino-middleware-progress.svg |
|||
[npm-downloads]: https://img.shields.io/npm/dt/neutrino-middleware-progress.svg |
|||
[npm-url]: https://npmjs.org/package/neutrino-middleware-progress |
|||
[slack-image]: https://neutrino-slack.herokuapp.com/badge.svg |
|||
[slack-url]: https://neutrino-slack.herokuapp.com/ |
@ -1,60 +0,0 @@ |
|||
# Neutrino Progress Middleware |
|||
[![NPM version][npm-image]][npm-url] [![NPM downloads][npm-downloads]][npm-url] [![Join Slack][slack-image]][slack-url] |
|||
|
|||
`neutrino-middleware-progress` is Neutrino middleware for displaying a progress bar showing the progress of a build. |
|||
|
|||
## Requirements |
|||
|
|||
- Node.js v6.9+ |
|||
- Yarn or npm client |
|||
- Neutrino v5 |
|||
|
|||
## Installation |
|||
|
|||
`neutrino-middleware-progress` can be installed via the Yarn or npm clients. |
|||
|
|||
#### Yarn |
|||
|
|||
```bash |
|||
❯ yarn add neutrino-middleware-progress |
|||
``` |
|||
|
|||
#### npm |
|||
|
|||
```bash |
|||
❯ npm install --save neutrino-middleware-progress |
|||
``` |
|||
|
|||
## Usage |
|||
|
|||
`neutrino-middleware-progress` can be consumed from the Neutrino API, middleware, or presets. Require this package |
|||
and plug it into Neutrino: |
|||
|
|||
```js |
|||
const progress = require('neutrino-middleware-progress'); |
|||
|
|||
neutrino.use(progress); |
|||
``` |
|||
|
|||
## Customization |
|||
|
|||
`neutrino-middleware-progress` creates some conventions to make overriding the configuration easier once you are ready to |
|||
make changes. |
|||
|
|||
### Plugins |
|||
|
|||
The following is a list of plugins and their identifiers which can be overridden: |
|||
|
|||
- `progress`: Displays a bar showing progression of build. |
|||
|
|||
## Contributing |
|||
|
|||
This preset is part of the [neutrino-dev](https://github.com/mozilla-neutrino/neutrino-dev) repository, a monorepo |
|||
containing all resources for developing Neutrino and its core presets. Follow the |
|||
[contributing guide](https://neutrino.js.org/contributing) for details. |
|||
|
|||
[npm-image]: https://img.shields.io/npm/v/neutrino-middleware-progress.svg |
|||
[npm-downloads]: https://img.shields.io/npm/dt/neutrino-middleware-progress.svg |
|||
[npm-url]: https://npmjs.org/package/neutrino-middleware-progress |
|||
[slack-image]: https://neutrino-slack.herokuapp.com/badge.svg |
|||
[slack-url]: https://neutrino-slack.herokuapp.com/ |
@ -1,3 +0,0 @@ |
|||
const ProgressBarPlugin = require('progress-bar-webpack-plugin'); |
|||
|
|||
module.exports = ({ config }) => config.plugin('progress').use(ProgressBarPlugin); |
@ -1,26 +0,0 @@ |
|||
{ |
|||
"name": "neutrino-middleware-progress", |
|||
"version": "5.0.0", |
|||
"description": "Neutrino middleware for displaying a progress bar during compilation", |
|||
"main": "index.js", |
|||
"keywords": [ |
|||
"neutrino", |
|||
"neutrino-middleware", |
|||
"progress", |
|||
"bar" |
|||
], |
|||
"author": "Eli Perelman <eli@eliperelman.com>", |
|||
"license": "MPL-2.0", |
|||
"repository": "https://github.com/mozilla-neutrino/neutrino-dev/tree/master/packages/neutrino-middleware-progress", |
|||
"homepage": "https://neutrino.js.org", |
|||
"bugs": "https://github.com/mozilla-neutrino/neutrino-dev/issues", |
|||
"dependencies": { |
|||
"progress-bar-webpack-plugin": "^1.9.3" |
|||
}, |
|||
"devDependencies": { |
|||
"webpack": "^2.2.1" |
|||
}, |
|||
"peerDependencies": { |
|||
"neutrino": "^5.0.0" |
|||
} |
|||
} |
File diff suppressed because it is too large
@ -1,23 +1,23 @@ |
|||
import test from 'ava'; |
|||
import { validate } from 'webpack'; |
|||
import Neutrino from 'neutrino'; |
|||
import { Neutrino } from 'neutrino'; |
|||
|
|||
test('loads preset', t => { |
|||
t.notThrows(() => require('..')); |
|||
}); |
|||
|
|||
test('uses preset', t => { |
|||
const api = new Neutrino(); |
|||
const api = Neutrino(); |
|||
|
|||
t.notThrows(() => api.use(require('..'))); |
|||
}); |
|||
|
|||
test('valid preset', t => { |
|||
const api = new Neutrino(); |
|||
const api = Neutrino(); |
|||
|
|||
api.use(require('..')); |
|||
|
|||
const errors = validate(api.getWebpackConfig()); |
|||
const errors = validate(api.config.toConfig()); |
|||
|
|||
t.is(errors.length, 0); |
|||
}); |
@ -1,23 +1,23 @@ |
|||
import test from 'ava'; |
|||
import { validate } from 'webpack'; |
|||
import Neutrino from 'neutrino'; |
|||
import { Neutrino } from 'neutrino'; |
|||
|
|||
test('loads preset', t => { |
|||
t.notThrows(() => require('..')); |
|||
}); |
|||
|
|||
test('uses preset', t => { |
|||
const api = new Neutrino(); |
|||
const api = Neutrino(); |
|||
|
|||
t.notThrows(() => api.use(require('..'))); |
|||
}); |
|||
|
|||
test('valid preset', t => { |
|||
const api = new Neutrino(); |
|||
const api = Neutrino(); |
|||
|
|||
api.use(require('..')); |
|||
|
|||
const errors = validate(api.getWebpackConfig()); |
|||
const errors = validate(api.config.toConfig()); |
|||
|
|||
t.is(errors.length, 0); |
|||
}); |
@ -1,23 +1,23 @@ |
|||
import test from 'ava'; |
|||
import { validate } from 'webpack'; |
|||
import Neutrino from 'neutrino'; |
|||
import { Neutrino } from 'neutrino'; |
|||
|
|||
test('loads preset', t => { |
|||
t.notThrows(() => require('..')); |
|||
}); |
|||
|
|||
test('uses preset', t => { |
|||
const api = new Neutrino(); |
|||
const api = Neutrino(); |
|||
|
|||
t.notThrows(() => api.use(require('..'))); |
|||
}); |
|||
|
|||
test('valid preset', t => { |
|||
const api = new Neutrino(); |
|||
const api = Neutrino(); |
|||
|
|||
api.use(require('..')); |
|||
|
|||
const errors = validate(api.getWebpackConfig()); |
|||
const errors = validate(api.config.toConfig()); |
|||
|
|||
t.is(errors.length, 0); |
|||
}); |
|||
|
@ -0,0 +1,23 @@ |
|||
const { build } = require('../src'); |
|||
const ora = require('ora'); |
|||
|
|||
module.exports = (middleware, options) => { |
|||
const spinner = ora('Building project').start(); |
|||
|
|||
return build(middleware, options) |
|||
.fork((errors) => { |
|||
spinner.fail('Building project failed'); |
|||
errors.forEach((err) => { |
|||
console.error(err.stack || err); |
|||
err.details && console.error(err.details); |
|||
}); |
|||
process.exit(1); |
|||
}, (stats) => { |
|||
spinner.succeed('Building project completed'); |
|||
console.log(stats.toString({ |
|||
colors: true, |
|||
chunks: false, |
|||
children: false |
|||
})); |
|||
}); |
|||
}; |
@ -0,0 +1,7 @@ |
|||
const { inspect } = require('../src'); |
|||
|
|||
module.exports = (middleware, options) => inspect(middleware, options) |
|||
.fork((err) => { |
|||
console.error(err.stack || err); |
|||
process.exit(1); |
|||
}, console.log); |
@ -0,0 +1,35 @@ |
|||
const { start } = require('../src'); |
|||
const ora = require('ora'); |
|||
|
|||
module.exports = (middleware, options) => { |
|||
const spinner = ora('Building project').start(); |
|||
|
|||
return start(middleware, options) |
|||
.fork((errors) => { |
|||
spinner.fail('Building project failed'); |
|||
errors.forEach((err) => { |
|||
console.error(err.stack || err); |
|||
err.details && console.error(err.details); |
|||
}); |
|||
|
|||
process.exit(1); |
|||
}, (compiler) => { // eslint-disable-line consistent-return
|
|||
if (!compiler.options.devServer) { |
|||
return spinner.succeed('Build completed'); |
|||
} |
|||
|
|||
const { devServer } = compiler.options; |
|||
const protocol = devServer.https ? 'https' : 'http'; |
|||
const { host, port } = devServer; |
|||
|
|||
spinner.succeed(`Development server running on: ${protocol}://${host}:${port}`); |
|||
|
|||
const building = ora('Waiting for initial build to finish').start(); |
|||
|
|||
compiler.plugin('done', () => building.succeed('Build completed')); |
|||
compiler.plugin('compile', () => { |
|||
building.text = 'Source changed, re-compiling'; |
|||
building.start(); |
|||
}); |
|||
}); |
|||
}; |
@ -0,0 +1,7 @@ |
|||
const { test } = require('../src'); |
|||
|
|||
module.exports = (middleware, options) => test(middleware, options) |
|||
.fork((err) => { |
|||
console.error(err.stack || err); |
|||
process.exit(1); |
|||
}, Function.prototype); |
@ -0,0 +1,71 @@ |
|||
const Config = require('webpack-chain'); |
|||
const merge = require('deepmerge'); |
|||
const { List } = require('immutable-ext'); |
|||
const Future = require('fluture'); |
|||
const mitt = require('mitt'); |
|||
const { chain, defaultTo, pipe } = require('ramda'); |
|||
const { createPaths, normalizePath, resolveAny, requireSafe } = require('./utils'); |
|||
const build = require('./build'); |
|||
const inspect = require('./inspect'); |
|||
const start = require('./start'); |
|||
const test = require('./test'); |
|||
|
|||
const getOptions = (options = {}) => { |
|||
const root = normalizePath(process.cwd(), defaultTo('', options.root)); |
|||
const base = normalizePath(root); |
|||
const source = base(defaultTo('src', options.source)); |
|||
const output = base(defaultTo('build', options.build)); |
|||
const tests = base(defaultTo('test', options.tests)); |
|||
const node_modules = base(defaultTo('node_modules', options.node_modules)); // eslint-disable-line camelcase
|
|||
const entry = normalizePath(source, defaultTo('index.js', options.entry)); |
|||
|
|||
return merge(options, { root, source, output, tests, node_modules, entry }); |
|||
}; |
|||
|
|||
// Api :: () -> Object
|
|||
const Api = pipe(getOptions, (options) => { |
|||
const listeners = {}; |
|||
|
|||
const api = merge(mitt(listeners), { |
|||
listeners, |
|||
options, |
|||
commands: {}, |
|||
config: new Config(), |
|||
|
|||
// emitForAll :: String -> payload -> Promise
|
|||
emitForAll: (eventName, payload) => Promise |
|||
.all((api.listeners[eventName] || []).map(f => f(payload))), |
|||
|
|||
// register :: String command -> Future handler -> ()
|
|||
register: (command, handler) => api.commands[command] = handler, |
|||
|
|||
// requireMiddleware :: (Array String middleware) -> Future Error a
|
|||
requires: middleware => List(middleware).map(pipe( |
|||
createPaths(api.options.root), |
|||
resolveAny, |
|||
chain(requireSafe) |
|||
)), |
|||
|
|||
// requiresAndUses :: Future Error a -> Future Error a
|
|||
requiresAndUses: middleware => api.useRequires(api.requires(middleware)), |
|||
|
|||
// use :: Function middleware -> Object options -> IO ()
|
|||
use: (middleware, options = {}) => middleware(api, options), |
|||
|
|||
// useRequires :: Future Error a -> Future Error a
|
|||
useRequires: requires => requires |
|||
// For all middleware, pass it to api.use()
|
|||
.map(chain(Future.encase(api.use))) |
|||
// Fold the middleware down to a single Task/Future status
|
|||
.reduce((f, current) => f.chain(() => current), Future.of()) |
|||
}); |
|||
|
|||
api.register('build', build); |
|||
api.register('inspect', inspect); |
|||
api.register('start', start); |
|||
api.register('test', test); |
|||
|
|||
return api; |
|||
}); |
|||
|
|||
module.exports = Api; |
@ -0,0 +1,16 @@ |
|||
const webpack = require('webpack'); |
|||
const Future = require('fluture'); |
|||
const { webpackErrors } = require('./utils'); |
|||
|
|||
// build :: Object config -> Future (Array Error) Function
|
|||
const build = config => Future((reject, resolve) => { |
|||
const compiler = webpack(config); |
|||
|
|||
compiler.run((err, stats) => { |
|||
const errors = webpackErrors(err, stats); |
|||
|
|||
errors.length ? reject(errors) : resolve(stats); |
|||
}); |
|||
}); |
|||
|
|||
module.exports = build; |
@ -0,0 +1,19 @@ |
|||
const merge = require('deepmerge'); |
|||
const webpack = require('webpack'); |
|||
const DevServer = require('webpack-dev-server'); |
|||
const Future = require('fluture'); |
|||
|
|||
// devServer :: Object webpackConfig -> Future () Function
|
|||
const devServer = webpackConfig => new Future((reject, resolve) => { |
|||
const config = merge({ |
|||
devServer: { host: 'localhost', port: 5000, noInfo: true } |
|||
}, webpackConfig); |
|||
const { host, port } = config.devServer; |
|||
|
|||
const compiler = webpack(config); |
|||
const server = new DevServer(compiler, config.devServer); |
|||
|
|||
server.listen(port, host, () => resolve(compiler)); |
|||
}); |
|||
|
|||
module.exports = devServer; |
@ -0,0 +1,46 @@ |
|||
const Api = require('./api'); |
|||
const { partial } = require('ramda'); |
|||
const Future = require('fluture'); |
|||
const { getNodeEnv, toArray } = require('./utils'); |
|||
|
|||
// run :: (String command -> Array middleware -> Object options) -> Future Error a
|
|||
const run = (command, middleware, options) => { |
|||
const api = Api(options); |
|||
|
|||
process.env.NODE_ENV = getNodeEnv(command, api.options.args && api.options.args.env); |
|||
|
|||
// Require and use all middleware
|
|||
return api.requiresAndUses(middleware) |
|||
// Also grab any config overrides and merge it into the config at a higher precedence
|
|||
.map(() => api.config.merge(options.config)) |
|||
// Trigger all pre-events for the current command
|
|||
.chain(() => Future.fromPromise2(api.emitForAll, `pre${command}`, api.options.args)) |
|||
// Execute the command
|
|||
.chain(() => api.commands[command](api.config.toConfig())) |
|||
// Trigger all post-command events, resolving with the value of the command execution
|
|||
.chain(value => Future |
|||
.fromPromise2(api.emitForAll, command, api.options.args) |
|||
.chain(() => Future.of(value))) |
|||
.mapRej(toArray); |
|||
}; |
|||
|
|||
// build :: (Array middleware -> Object options) -> Future Error a
|
|||
const build = partial(run, ['build']); |
|||
|
|||
// inspect :: (Array middleware -> Object options) -> Future Error a
|
|||
const inspect = partial(run, ['inspect']); |
|||
|
|||
// start :: (Array middleware -> Object options) -> Future Error a
|
|||
const start = partial(run, ['start']); |
|||
|
|||
// test :: (Array middleware -> Object options) -> Future Error a
|
|||
const test = partial(run, ['test']); |
|||
|
|||
module.exports = { |
|||
Neutrino: Api, |
|||
run, |
|||
build, |
|||
inspect, |
|||
start, |
|||
test |
|||
}; |
@ -0,0 +1,9 @@ |
|||
const Future = require('fluture'); |
|||
const stringify = require('javascript-stringify'); |
|||
const sort = require('deep-sort-object'); |
|||
const { partialRight, pipe } = require('ramda'); |
|||
|
|||
// inspect :: Object config -> Future () String
|
|||
const inspect = pipe(sort, partialRight(stringify, [null, 2]), Future.of); |
|||
|
|||
module.exports = inspect; |
@ -1,72 +0,0 @@ |
|||
const { join, isAbsolute } = require('path'); |
|||
const { EventEmitter } = require('events'); |
|||
const Config = require('webpack-chain'); |
|||
const merge = require('deepmerge'); |
|||
const { defaultTo, identity } = require('ramda'); |
|||
const requireMiddleware = require('./requireMiddleware'); |
|||
const build = require('./webpack/build'); |
|||
const develop = require('./webpack/develop'); |
|||
const watch = require('./webpack/watch'); |
|||
|
|||
const normalizePath = (path, root) => (isAbsolute(path) ? path : join(root, path)); |
|||
|
|||
module.exports = class Neutrino extends EventEmitter { |
|||
constructor(options = {}) { |
|||
super(); |
|||
|
|||
const root = normalizePath(options.root || '', process.cwd()); |
|||
const source = normalizePath(options.source || 'src', root); |
|||
const output = normalizePath(options.output || 'build', root); |
|||
const tests = normalizePath(options.tests || 'test', root); |
|||
const node_modules = normalizePath(options.node_modules || 'node_modules', root); // eslint-disable-line camelcase
|
|||
const entry = normalizePath(options.entry || 'index.js', source); |
|||
|
|||
this.config = new Config(); |
|||
this.options = merge(options, { root, source, output, tests, node_modules, entry }); |
|||
} |
|||
|
|||
use(middleware, options = {}) { |
|||
middleware(this, options); |
|||
} |
|||
|
|||
import(middleware) { |
|||
this.require(middleware).forEach(middleware => this.use(middleware)); |
|||
} |
|||
|
|||
require(middleware) { |
|||
return requireMiddleware(middleware, this.options); |
|||
} |
|||
|
|||
getWebpackConfig() { |
|||
return this.config.toConfig(); |
|||
} |
|||
|
|||
emitForAll(eventName, payload) { |
|||
return Promise.all(this.listeners(eventName).map(fn => fn(payload))); |
|||
} |
|||
|
|||
build(args) { |
|||
return this.runCommand('build', args, build); |
|||
} |
|||
|
|||
start(args) { |
|||
return this.runCommand('start', args, this.getWebpackConfig().devServer ? develop : watch); |
|||
} |
|||
|
|||
test(args) { |
|||
return this.runCommand('test', args); |
|||
} |
|||
|
|||
runCommand(command, args = {}, fn = identity) { |
|||
process.env.NODE_ENV = defaultTo({ |
|||
build: 'production', |
|||
start: 'development', |
|||
test: 'test' |
|||
}[command], args.env); |
|||
|
|||
return this |
|||
.emitForAll(`pre${command}`, args) |
|||
.then(() => fn(this.getWebpackConfig())) |
|||
.then(() => this.emitForAll(command, args)); |
|||
} |
|||
} |
@ -1,36 +0,0 @@ |
|||
/* eslint-disable global-require*/ |
|||
const { join } = require('path'); |
|||
|
|||
const castToArray = val => (Array.isArray(val) ? val : [val]); |
|||
|
|||
function requirePath(path, middleware) { |
|||
try { |
|||
return require(path); |
|||
} catch (exception) { |
|||
if (!/Cannot find module/.test(exception.message)) { |
|||
exception.message = `Neutrino was unable to load the module '${middleware}'. ` + |
|||
`Ensure this module exports a function and is free from errors.\n${exception.message}`; |
|||
throw exception; |
|||
} |
|||
|
|||
return undefined; |
|||
} |
|||
} |
|||
|
|||
module.exports = function requireMiddleware(middleware, options = {}) { |
|||
const root = options.root || process.cwd(); |
|||
|
|||
return castToArray(middleware).map((middleware) => { |
|||
const path = [ |
|||
join(root, middleware), |
|||
join(root, 'node_modules', middleware) |
|||
].find(path => requirePath(path)); |
|||
|
|||
if (!path) { |
|||
throw new Error(`Neutrino cannot find a module with the name or path '${middleware}'. ` + |
|||
'Ensure this module can be found relative to the root of the project.'); |
|||
} |
|||
|
|||
return require(path); |
|||
}); |
|||
}; |
@ -0,0 +1,6 @@ |
|||
const { ifElse, propSatisfies } = require('ramda'); |
|||
const devServer = require('./devServer'); |
|||
const watch = require('./watch'); |
|||
|
|||
// start :: Object options -> Future (Array Error) Function
|
|||
module.exports = ifElse(propSatisfies(Boolean, 'devServer'), devServer, watch); |
@ -0,0 +1,5 @@ |
|||
const Future = require('fluture'); |
|||
const { identity } = require('ramda'); |
|||
|
|||
// test :: Object options -> Future () Function
|
|||
module.exports = () => Future.of(identity); |
@ -0,0 +1,64 @@ |
|||
const Future = require('fluture'); |
|||
const { cond, curry, defaultTo, identity, map, memoize, of, partialRight, pipe, reduce, T } = require('ramda'); |
|||
const { List } = require('immutable-ext'); |
|||
const { isAbsolute, join } = require('path'); |
|||
const optional = require('optional'); |
|||
|
|||
// any :: List -> Future a b
|
|||
const any = reduce(Future.or, Future.reject('empty list')); |
|||
|
|||
// createPaths :: (String -> String) -> List String
|
|||
const createPaths = curry((base, middleware) => List.of( |
|||
join(base, middleware), |
|||
join(base, 'node_modules', middleware), |
|||
middleware |
|||
)); |
|||
|
|||
// getNodeEnv :: String command -> String? env -> String
|
|||
const getNodeEnv = (command = 'start', env) => defaultTo({ |
|||
build: 'production', |
|||
start: 'development', |
|||
test: 'test' |
|||
}[command] || 'development', env); |
|||
|
|||
// getPackageJson :: () -> Object
|
|||
const getPackageJson = memoize(pipe( |
|||
process.cwd, |
|||
partialRight(join, ['package.json']), |
|||
optional, |
|||
defaultTo({}) |
|||
)); |
|||
|
|||
// normalize :: String base -> String path -> String
|
|||
const normalizePath = curry((base, path) => (isAbsolute(path) ? path : join(base, path))); |
|||
|
|||
// resolveSafe :: String -> Future Error String
|
|||
const resolveSafe = Future.encase(require.resolve); |
|||
|
|||
// requireSafe :: String -> Future Error a
|
|||
const requireSafe = Future.encase(require); |
|||
|
|||
// resolveAny :: List -> Future Error String
|
|||
const resolveAny = pipe(map(resolveSafe), any); |
|||
|
|||
// toArray :: a -> Array
|
|||
const toArray = cond([ |
|||
[Array.isArray, identity], |
|||
[T, of] |
|||
]); |
|||
|
|||
// webpackErrors :: (Error|Array Error err -> Object stats) -> Array Error
|
|||
const webpackErrors = (err, stats) => (err ? toArray(err) : stats.toJson().errors); |
|||
|
|||
module.exports = { |
|||
any, |
|||
createPaths, |
|||
getNodeEnv, |
|||
getPackageJson, |
|||
normalizePath, |
|||
requireSafe, |
|||
resolveAny, |
|||
resolveSafe, |
|||
toArray, |
|||
webpackErrors |
|||
}; |
@ -0,0 +1,16 @@ |
|||
const webpack = require('webpack'); |
|||
const Future = require('fluture'); |
|||
const { webpackErrors } = require('./utils'); |
|||
|
|||
// watch :: Object config -> Future (Array Error) ()
|
|||
const watch = config => new Future((reject, resolve) => { |
|||
const compiler = webpack(config); |
|||
|
|||
compiler.watch(config.watchOptions || {}, (err, stats) => { |
|||
const errors = webpackErrors(err, stats); |
|||
|
|||
errors.length ? reject(errors) : resolve(compiler); |
|||
}); |
|||
}); |
|||
|
|||
module.exports = watch; |
@ -1,10 +0,0 @@ |
|||
const webpack = require('webpack'); |
|||
const { handle, logErrors, logStats } = require('./utils'); |
|||
|
|||
module.exports = config => new Promise((resolve, reject) => { |
|||
const compiler = webpack(config); |
|||
|
|||
compiler.run(handle((errors, stats) => ( |
|||
errors.length ? reject(logErrors(errors)) : resolve(logStats(stats)) |
|||
))); |
|||
}); |
@ -1,28 +0,0 @@ |
|||
const ora = require('ora'); |
|||
const merge = require('deepmerge'); |
|||
const webpack = require('webpack'); |
|||
const DevServer = require('webpack-dev-server'); |
|||
|
|||
module.exports = _config => new Promise((resolve) => { |
|||
const defaultDevServer = { host: 'localhost', port: 5000, noInfo: true }; |
|||
const config = merge({ devServer: defaultDevServer }, _config); |
|||
const protocol = config.devServer.https ? 'https' : 'http'; |
|||
const { host, port } = config.devServer; |
|||
|
|||
const starting = ora('Starting development server').start(); |
|||
const compiler = webpack(config); |
|||
const server = new DevServer(compiler, config.devServer); |
|||
const building = ora('Waiting for initial build to finish').start(); |
|||
|
|||
server.listen(port, host, () => { |
|||
starting.succeed(`Development server running on: ${protocol}://${host}:${port}`); |
|||
|
|||
compiler.plugin('done', () => building.succeed('Build completed')); |
|||
compiler.plugin('compile', () => { |
|||
building.text = 'Source changed, re-compiling'; |
|||
building.start(); |
|||
}); |
|||
}); |
|||
|
|||
process.on('SIGINT', resolve); |
|||
}); |
@ -1,22 +0,0 @@ |
|||
module.exports.handle = fn => (err, stats) => fn(err ? [err] : stats.toJson().errors, stats); |
|||
|
|||
module.exports.logStats = (stats) => { |
|||
console.log(stats.toString({ |
|||
colors: true, |
|||
chunks: false, |
|||
children: false |
|||
})); |
|||
|
|||
return stats; |
|||
}; |
|||
|
|||
module.exports.logErrors = (errors) => { |
|||
errors.forEach((err) => { |
|||
console.error(err.stack || err); |
|||
if (err.details) { |
|||
console.error(err.details); |
|||
} |
|||
}); |
|||
|
|||
return errors; |
|||
}; |
@ -1,15 +0,0 @@ |
|||
const webpack = require('webpack'); |
|||
const ora = require('ora'); |
|||
const { handle, logErrors } = require('./utils'); |
|||
|
|||
module.exports = config => new Promise((resolve) => { |
|||
const compiler = webpack(config); |
|||
const building = ora('Waiting for initial build to finish').start(); |
|||
|
|||
const watcher = compiler.watch(config.watchOptions || {}, handle((errors) => { |
|||
building.succeed('Build completed'); |
|||
logErrors(errors); |
|||
})); |
|||
|
|||
process.on('SIGINT', () => watcher.close(resolve)); |
|||
}); |
@ -1,45 +0,0 @@ |
|||
import { join } from 'path'; |
|||
import { outputFile as fsOutputFile, remove as fsRemove } from 'fs-extra'; |
|||
import pify from 'pify'; |
|||
import test from 'ava'; |
|||
import requireMiddleware from '../src/requireMiddleware'; |
|||
|
|||
const cwd = process.cwd(); |
|||
const outputFile = pify(fsOutputFile); |
|||
const remove = pify(fsRemove); |
|||
|
|||
const rootPath = join(__dirname, 'test-module'); |
|||
const rootMiddlewarePath = join(rootPath, 'middleware.js'); |
|||
const errorMiddlewarePath = join(rootPath, 'errorMiddleware.js'); |
|||
const modulePath = join(rootPath, 'node_modules', 'mymodule'); |
|||
const moduleMiddlewarePath = join(modulePath, 'index.js'); |
|||
|
|||
test.before(async (t) => { |
|||
await Promise.all([ |
|||
outputFile(rootMiddlewarePath, 'module.exports = "root"'), |
|||
outputFile(errorMiddlewarePath, '[;'), |
|||
outputFile(moduleMiddlewarePath, 'module.exports = "mymodule"') |
|||
]) |
|||
process.chdir(rootPath); |
|||
}); |
|||
|
|||
test.after.always(async (t) => { |
|||
await remove(rootPath); |
|||
process.chdir(cwd); |
|||
}); |
|||
|
|||
test('requires middleware relative to root', t => { |
|||
t.is(requireMiddleware('middleware')[0], 'root'); |
|||
}); |
|||
|
|||
test('requires middleware from root/node_modules', t => { |
|||
t.is(requireMiddleware('mymodule')[0], 'mymodule'); |
|||
}); |
|||
|
|||
test('throws if middleware contains error', t => { |
|||
t.throws(() => requireMiddleware('errorMiddleware')); |
|||
}); |
|||
|
|||
test('throws if middleware cannot be found', t => { |
|||
t.throws(() => requireMiddleware('notExistent')); |
|||
}); |
@ -0,0 +1,52 @@ |
|||
import { join } from 'path'; |
|||
import { outputFile as fsOutputFile, remove as fsRemove } from 'fs-extra'; |
|||
import pify from 'pify'; |
|||
import test from 'ava'; |
|||
import { Neutrino } from '../src'; |
|||
|
|||
const cwd = process.cwd(); |
|||
const outputFile = pify(fsOutputFile); |
|||
const remove = pify(fsRemove); |
|||
const rootPath = join(__dirname, 'test-module'); |
|||
const rootMiddlewarePath = join(rootPath, 'middleware.js'); |
|||
const errorMiddlewarePath = join(rootPath, 'errorMiddleware.js'); |
|||
const modulePath = join(rootPath, 'node_modules', 'alpha'); |
|||
const moduleMiddlewarePath = join(modulePath, 'index.js'); |
|||
|
|||
test.before(async () => { |
|||
await Promise.all([ |
|||
outputFile(rootMiddlewarePath, 'module.exports = () => "root"'), |
|||
outputFile(errorMiddlewarePath, '[;'), |
|||
outputFile(moduleMiddlewarePath, 'module.exports = () => "alpha"') |
|||
]); |
|||
process.chdir(rootPath); |
|||
}); |
|||
|
|||
test.after.always(async () => { |
|||
await remove(rootPath); |
|||
process.chdir(cwd); |
|||
}); |
|||
|
|||
test('requires middleware relative to root', t => { |
|||
const api = Neutrino(); |
|||
|
|||
api.requiresAndUses(['middleware']).value(v => t.is(v, 'root')); |
|||
}); |
|||
|
|||
test('requires middleware from root/node_modules', t => { |
|||
const api = Neutrino(); |
|||
|
|||
api.requiresAndUses(['alpha']).value(v => t.is(v, 'alpha')); |
|||
}); |
|||
|
|||
test('forks with error middleware contains error', async (t) => { |
|||
const api = Neutrino(); |
|||
|
|||
await t.throws(api.requiresAndUses(['errorMiddleware']).promise()); |
|||
}); |
|||
|
|||
test('throws if middleware cannot be found', async (t) => { |
|||
const api = Neutrino(); |
|||
|
|||
await t.throws(api.requiresAndUses(['nonExistent']).promise()); |
|||
}); |
@ -0,0 +1,32 @@ |
|||
import test from 'ava'; |
|||
import commands from '../src'; |
|||
|
|||
test('run::build uses "production" NODE_ENV', t => { |
|||
commands.run('build'); |
|||
t.is(process.env.NODE_ENV, 'production'); |
|||
}); |
|||
|
|||
test('build uses "production" NODE_ENV', t => { |
|||
commands.build(); |
|||
t.is(process.env.NODE_ENV, 'production'); |
|||
}); |
|||
|
|||
test('start uses "development" NODE_ENV', t => { |
|||
commands.start(); |
|||
t.is(process.env.NODE_ENV, 'development'); |
|||
}); |
|||
|
|||
test('test uses "test" NODE_ENV', t => { |
|||
commands.test(); |
|||
t.is(process.env.NODE_ENV, 'test'); |
|||
}); |
|||
|
|||
test('inspect uses "development" NODE_ENV by default', t => { |
|||
commands.inspect(); |
|||
t.is(process.env.NODE_ENV, 'development'); |
|||
}); |
|||
|
|||
test('inspect uses overridden NODE_ENV', t => { |
|||
commands.inspect([], { args: { env: 'production' } }); |
|||
t.is(process.env.NODE_ENV, 'production'); |
|||
}); |
Loading…
Reference in new issue