Skip to content

Commit

Permalink
feat(docz-core): use websockets instead of generate json to process e…
Browse files Browse the repository at this point in the history
…ntries
  • Loading branch information
pedronauck committed May 22, 2018
1 parent 986ba65 commit e0773a0
Show file tree
Hide file tree
Showing 13 changed files with 162 additions and 100 deletions.
4 changes: 2 additions & 2 deletions examples/basic/src/index.mdx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
---
name: Overview
name: Getting Started
route: /
order: 1
---

# Overview
# Getting Started

A design system can help establish a common vocabulary between everyone in an organization. That’s why I’ve spent a great deal of time coming up with structure and naming for Vue Design System that would make sense. To start opening it up, let’s go through each layer in detail and what the terms mean:

Expand Down
2 changes: 2 additions & 0 deletions packages/docz-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"webpack-chain": "^4.6.0",
"webpack-serve": "^0.3.2",
"webpackbar": "^2.6.1",
"ws": "^5.1.1",
"yargs": "^11.0.0"
},
"devDependencies": {
Expand All @@ -82,6 +83,7 @@
"@types/resolve": "^0.0.7",
"@types/webpack": "^4.1.3",
"@types/webpack-chain": "^4.0.2",
"@types/ws": "^5.1.1",
"@types/yargs": "^11.0.0",
"rollup-plugin-cpy": "^1.0.0",
"tslint": "^5.10.0",
Expand Down
7 changes: 6 additions & 1 deletion packages/docz-core/src/Bundler.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import { Plugin } from './Plugin'
import { Config } from './commands/args'

export interface Server {
close: () => void
on: (event: string, cb: (server: any) => void) => void
}

export interface BundlerServer {
start(): any
start(): Promise<Server>
}

export type ConfigFn<C> = () => C
Expand Down
33 changes: 6 additions & 27 deletions packages/docz-core/src/Entries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@ const compiled = (file: string) =>
stream.on('error', err => reject(err))
})

const stringify = (obj: any) => JSON.stringify(obj, null, 2)

const writeStructuredFiles = async (config: Config): Promise<void> => {
const { plugins, title, description, theme } = config

Expand All @@ -55,6 +53,7 @@ const writeStructuredFiles = async (config: Config): Promise<void> => {
const rawAppJs = app({
theme,
wrappers,
websocketUrl: `ws://${config.websocketHost}:${config.websocketPort}`,
})

const rawIndexJs = js({
Expand All @@ -72,26 +71,9 @@ const writeStructuredFiles = async (config: Config): Promise<void> => {
await touch(paths.indexHtml, rawIndexHtml)
}

const writeDataAndImports = async (
entries: EntryMap,
config: Config
): Promise<void> => {
const { title, description, theme } = config
const writeImports = async (entries: EntryMap): Promise<void> => {
const imports = await compiled('imports.tpl.js')

const rawImportsJs = imports({
entries,
})

const rawData = stringify({
title,
description,
theme,
entries,
})

await touch(paths.importsJs, rawImportsJs)
await touch(paths.dataJson, rawData)
await touch(paths.importsJs, imports({ entries }))
}

export type EntryMap = Record<string, Entry>
Expand All @@ -100,14 +82,11 @@ export class Entries {
public static async write(config: Config, entries: EntryMap): Promise<void> {
mkd(paths.docz)
await writeStructuredFiles(config)
await writeDataAndImports(entries, config)
await writeImports(entries)
}

public static async rewrite(config: Config): Promise<void> {
const entries = new Entries(config)
const map = await entries.getMap()

await writeDataAndImports(map, config)
public static async rewrite(map: EntryMap): Promise<void> {
await writeImports(map)
}

public config: Config
Expand Down
9 changes: 4 additions & 5 deletions packages/docz-core/src/bundlers/webpack/devserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,22 @@ export const devServerConfig = (
compiler: Compiler,
config: Configuration
) => {
const { port, host } = args
const nonExistentDir = path.resolve(__dirname, 'non-existent')
const logLevel = (level: string) => (args.debug ? 'debug' : level)

return {
compiler,
host,
port,
host: args.host,
port: args.port,
content: [nonExistentDir],
logLevel: logLevel('error'),
dev: {
logLevel: logLevel('silent'),
},
hot: {
logLevel: logLevel('error'),
reload: false,
logLevel: logLevel('error'),
},
logLevel: logLevel('error'),
add: (app: any) => {
app.use(
convert(
Expand Down
9 changes: 8 additions & 1 deletion packages/docz-core/src/bundlers/webpack/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,14 @@ export const server = (args: Config) => (config: CFG): BundlerServer => {
const devserver = devServerConfig(args, compiler, config)

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

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

Expand Down
10 changes: 10 additions & 0 deletions packages/docz-core/src/commands/args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export interface Argv {
protocol: string
host: string
port: number
websocketPort: number
websocketHost: string
}

export interface Config extends Argv {
Expand Down Expand Up @@ -67,4 +69,12 @@ export const args = (yargs: any) => {
type: 'number',
default: process.env.PORT || 3000,
})
yargs.positional('websocketHost', {
type: 'string',
default: process.env.HOST || '0.0.0.0',
})
yargs.positional('websocketPort', {
type: 'number',
default: process.env.WEBSOCKET_PORT || 8089,
})
}
68 changes: 52 additions & 16 deletions packages/docz-core/src/commands/dev.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,70 @@
import { load } from 'load-cfg'
import chokidar from 'chokidar'
import WebSocket from 'ws'

import * as paths from '../config/paths'
import { Config } from './args'

import { Entries } from '../Entries'
import { Entries, EntryMap } from '../Entries'
import { webpack } from '../bundlers'

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

const writeEntriesAndWatch = async (config: Config) => {
const entries = new Entries(config)
const map = await entries.getMap()
const entriesData = (entries: EntryMap, config: Config) =>
JSON.stringify({
type: 'entries data',
data: {
entries,
title: config.title,
description: config.description,
},
})

const handleUpdate = async () => Entries.rewrite(config)
const handleRaw = async (event: string, path: string, details: any) => {
if (details.event === 'moved' && details.type === 'directory') {
handleUpdate()
}
}
const updateEntries = (socket: WebSocket) => (config: Config) => async () => {
const newEntries = new Entries(config)
const newMap = await newEntries.getMap()

await Entries.rewrite(newMap)
socket.send(entriesData(newMap, config))
}

const processEntries = (config: Config) => async (server: any) => {
const entries = new Entries(config)
const map = await entries.getMap()
const watcher = chokidar.watch(config.files, {
ignored: /(^|[\/\\])\../,
})

watcher
.on('change', handleUpdate)
.on('unlink', handleUpdate)
.on('raw', handleRaw)
const wss = new WebSocket.Server({
server,
host: config.websocketHost,
port: config.websocketPort,
})

const handleClose = () => {
watcher.close()
wss.close()
}

const handleConnection = async (socket: WebSocket) => {
const update = updateEntries(socket)

socket.send(entriesData(map, config))

watcher.on('change', update(config))
watcher.on('unlink', update(config))
watcher.on('raw', (event: string, path: string, details: any) => {
if (details.event === 'moved' && details.type === 'directory') {
update(config)()
}
})
}

wss.on('connection', handleConnection)
server.on('close', handleClose)
process.on('exit', handleClose)
process.on('SIGINT', handleClose)

await Entries.write(config, map)
}
Expand All @@ -44,7 +80,7 @@ export const dev = async (args: Config) => {
const config = load('docz', { ...args, ...INITIAL_CONFIG })
const bundler = webpack(config)
const server = await bundler.createServer(bundler.getConfig())
const app = await server.start()

await writeEntriesAndWatch(config)
server.start()
app.on('listening', processEntries(args))
}
2 changes: 0 additions & 2 deletions packages/docz-core/src/config/paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ export interface Paths {
appJs: string
indexJs: string
indexHtml: string
dataJson: string
}

export const templates = path.join(resolve.sync('docz-core'), '../templates')
Expand All @@ -55,5 +54,4 @@ export const dist = path.resolve(docz, 'dist/')
export const importsJs = path.resolve(docz, 'imports.js')
export const appJs = path.resolve(docz, 'app.jsx')
export const indexJs = path.resolve(docz, 'index.jsx')
export const dataJson = path.resolve(docz, 'data.json')
export const indexHtml = path.resolve(docz, 'index.html')
34 changes: 28 additions & 6 deletions packages/docz-core/templates/app.tpl.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ import React from 'react'
import { hot } from 'react-hot-loader'
import { Theme } from '<%- theme %>'

import { imports } from './imports'
import data from './data.json'

const socket = new WebSocket(`<%- websocketUrl %>`)
const _wrappers = [<% if (wrappers) {%><%- wrappers %><%}%>]

const recursiveWrappers = ([Wrapper, ...rest], props) => (
Expand All @@ -16,8 +14,32 @@ const recursiveWrappers = ([Wrapper, ...rest], props) => (
const Wrapper = props =>
_wrappers.length ? recursiveWrappers(_wrappers, props) : props.children

const App = () => (
<Theme data={data} imports={imports} wrapper={Wrapper} />
)
class App extends React.Component {
state = {
data: {},
imports: {}
}

static getDerivedStateFromProps(nextProps, prevState) {
return {
data: prevState.data,
imports: nextProps.imports
}
}

async componentDidMount() {
socket.onmessage = ev => {
const message = JSON.parse(ev.data)

if (message.type === 'entries data') {
this.setState({ data: message.data })
}
}
}

render() {
return <Theme {...this.state} wrapper={Wrapper} />
}
}

export default hot(module)(App)
17 changes: 14 additions & 3 deletions packages/docz-core/templates/index.tpl.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React from 'react'
import { render } from 'react-dom'
import ReactDOM from 'react-dom'

import { imports } from './imports'
import App from './app'

const _beforeRenders = [<% if (beforeRenders) {%><%- beforeRenders %><%}%>]
Expand All @@ -8,5 +10,14 @@ const _afterRenders = [<% if (afterRenders) {%><%- afterRenders %><%}%>]
const beforeRender = () => _beforeRenders.forEach(f => f && f())
const afterRender = () => _afterRenders.forEach(f => f && f())

beforeRender()
render(<App />, document.querySelector('#root'), afterRender)
const root = document.querySelector('#root')
const render = (Component = App) => {
beforeRender()
ReactDOM.render( <Component imports={imports} />, root, afterRender)
}

if (module.hot) {
module.hot.accept('./imports', () => render(App))
}

render(App)
Loading

0 comments on commit e0773a0

Please sign in to comment.