Skip to content

Commit

Permalink
chore(docz-core): refac build command
Browse files Browse the repository at this point in the history
  • Loading branch information
pedronauck committed May 27, 2018
1 parent ef7abd2 commit 2bd3b5b
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 177 deletions.
10 changes: 9 additions & 1 deletion packages/docz-core/src/Bundler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,28 @@ export interface BundlerServer {
}

export type ServerFn<C> = (config: C) => BundlerServer | Promise<BundlerServer>
export type BuildFn<C> = (config: C) => void

export interface BundlerConstructor<Config> {
args: Args
config: Config
server: ServerFn<Config>
build: BuildFn<Config>
}

export class Bundler<C = any> {
private readonly args: Args
private config: C
private server: ServerFn<C>
private builder: BuildFn<C>

constructor(params: BundlerConstructor<C>) {
const { args, config, server } = params
const { args, config, server, build } = params

this.args = args
this.config = config
this.server = server
this.builder = build
}

public getConfig(): C {
Expand All @@ -48,6 +52,10 @@ export class Bundler<C = any> {
return server
}

public async build(): Promise<void> {
this.builder(this.config)
}

private reduceWithPlugins(dev: boolean): any {
return (config: C, plugin: Plugin) =>
plugin.bundlerConfig(config, dev) || config
Expand Down
35 changes: 15 additions & 20 deletions packages/docz-core/src/DataServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,23 @@ const isSocketOpened = (socket: WS) => socket.readyState === WS.OPEN

export interface DataServerOpts {
server: any
port: number
host: string
config: Config
}

export class DataServer {
private server: WS.Server
private config: Config

constructor({ server, port, host, config }: DataServerOpts) {
constructor({ server, config }: DataServerOpts) {
this.config = config
this.server = new WS.Server({
server,
port,
host,
port: config.websocketPort,
host: config.websocketHost,
})

this.config = {
...config,
websocketPort: port,
}
}

public async processEntries(): Promise<void> {
const config = this.config
const entries = new Entries(config)
public async processEntries(entries: Entries): Promise<void> {
const watcher = chokidar.watch(this.config.files, {
ignored: /(^|[\/\\])\../,
})
Expand All @@ -56,9 +48,6 @@ export class DataServer {

this.server.on('connection', handleConnection)
this.server.on('close', () => watcher.close())

await Entries.writeApp(config, true)
await Entries.writeImports(await entries.getMap())
}

public async processThemeConfig(): Promise<void> {
Expand All @@ -67,9 +56,9 @@ export class DataServer {
const handleConnection = async (socket: WS) => {
const update = this.updateConfig(socket)

watcher.on('add', update)
watcher.on('change', update)
watcher.on('unlink', update)
watcher.on('add', () => update())
watcher.on('change', () => update())
watcher.on('unlink', () => update())

update()
}
Expand Down Expand Up @@ -109,9 +98,15 @@ export class DataServer {
}

private updateConfig(socket: WS): () => void {
const config = load('docz', { ...this.config }, true)
const initialConfig = {
title: this.config.title,
description: this.config.description,
themeConfig: this.config.themeConfig,
}

return () => {
const config = load('docz', initialConfig, true)

if (isSocketOpened(socket)) {
socket.send(this.configData(config))
}
Expand Down
125 changes: 125 additions & 0 deletions packages/docz-core/src/bundlers/webpack/build.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import * as fs from 'fs-extra'
import chalk from 'chalk'
import logger from 'signale'
import webpack, { Configuration } from 'webpack'
import FSR from 'react-dev-utils/FileSizeReporter'
import formatWebpackMessages from 'react-dev-utils/formatWebpackMessages'
import printBuildError from 'react-dev-utils/printBuildError'

import * as paths from '../../config/paths'

process.env.BABEL_ENV = process.env.BABEL_ENV || 'production'
process.env.NODE_ENV = process.env.NODE_ENV || 'production'

const { measureFileSizesBeforeBuild, printFileSizesAfterBuild } = FSR
const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024
const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024

const hasCiEnvVar = () =>
process.env.CI &&
(typeof process.env.CI !== 'string' ||
process.env.CI.toLowerCase() !== 'false')

const copyPublicFolder = async (): Promise<void> => {
if (await fs.pathExists(paths.appPublic)) {
await fs.copySync(paths.appPublic, paths.distPublic, {
dereference: true,
filter: file => file !== paths.indexHtml,
})
}
}

const compile = (config: Configuration) =>
new Promise((resolve, reject) => {
let compiler
try {
compiler = webpack(config)
} catch (err) {
onError(err)
}
compiler &&
compiler.run((err, stats) => {
if (err) reject(err)
resolve(stats)
})
})

const builder = async (config: Configuration, previousFileSizes: any) => {
logger.start('Creating an optimized production build...')

return new Promise(async (resolve, reject) => {
try {
const stats: any = await compile(config)
const messages = formatWebpackMessages(stats.toJson({}, true))

if (messages.errors.length) {
return reject(new Error(messages.errors.join('\n\n')))
}

if (hasCiEnvVar() && messages.warnings.length) {
logger.warn(
'\nTreating warnings as errors because process.env.CI = true.\n' +
'Most CI servers set it automatically.\n'
)
return reject(new Error(messages.warnings.join('\n\n')))
}

return resolve({
stats,
previousFileSizes,
warnings: messages.warnings,
})
} catch (err) {
reject(err)
}
})
}

const onSuccess = ({ stats, previousFileSizes, warnings }: any) => {
if (warnings.length) {
logger.warn('Compiled with warnings.\n')
logger.warn(warnings.join('\n\n'))
logger.warn(
'\nSearch for the ' +
chalk.underline(chalk.yellow('keywords')) +
' to learn more about each warning.'
)
logger.warn(
'To ignore, add ' +
chalk.cyan('// eslint-disable-next-line') +
' to the line before.\n'
)
} else {
logger.success(chalk.green('Compiled successfully.\n'))
}

logger.log('File sizes after gzip:\n')
printFileSizesAfterBuild(
stats,
previousFileSizes,
paths.dist,
WARN_AFTER_BUNDLE_GZIP_SIZE,
WARN_AFTER_CHUNK_GZIP_SIZE
)
logger.log()
}

const onError = (err: Error) => {
logger.fatal(chalk.red('Failed to compile.\n'))
printBuildError(err)
process.exit(1)
}

export const build = async (config: Configuration) => {
try {
const previousFileSizes = await measureFileSizesBeforeBuild(paths.dist)

await fs.emptyDir(paths.dist)
await copyPublicFolder()

const result = await builder(config, previousFileSizes)
onSuccess(result)
} catch (err) {
onError(err)
}
}
31 changes: 6 additions & 25 deletions packages/docz-core/src/bundlers/webpack/index.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,20 @@
import webpack, { Configuration as CFG } from 'webpack'
import serve from 'webpack-serve'
import detectPort from 'detect-port'
import { Configuration as CFG } from 'webpack'

import { devServerConfig } from './devserver'
import { createConfig } from './config'
import { Bundler, BundlerServer } from '../../Bundler'
import { Bundler } from '../../Bundler'
import { Config as Args } from '../../commands/args'
import { createConfig } from './config'
import { server } from './server'
import { build } from './build'

export type Env = 'production' | 'development'

export const server = (args: Args) => async (
config: CFG
): Promise<BundlerServer> => {
const compiler = webpack(config)
const port = await detectPort(args.port)
const devserver = devServerConfig({ ...args, port }, compiler, config)

return {
start: async () => {
const instance = await serve(devserver)

return {
on: instance.on,
close: instance.close,
}
},
}
}

export const bundler = (args: Args, env: Env): Bundler<CFG> => {
const config: any = createConfig(args, env).toConfig()

return new Bundler({
args,
config,
build,
server: server(args),
})
}
26 changes: 26 additions & 0 deletions packages/docz-core/src/bundlers/webpack/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import webpack, { Configuration as CFG } from 'webpack'
import serve from 'webpack-serve'
import detectPort from 'detect-port'

import { devServerConfig } from './devserver'
import { BundlerServer } from '../../Bundler'
import { Config as Args } from '../../commands/args'

export const server = (args: Args) => async (
config: CFG
): Promise<BundlerServer> => {
const compiler = webpack(config)
const port = await detectPort(args.port)
const devserver = devServerConfig({ ...args, port }, compiler, config)

return {
start: async () => {
const instance = await serve(devserver)

return {
on: instance.on,
close: instance.close,
}
},
}
}
Loading

0 comments on commit 2bd3b5b

Please sign in to comment.