diff --git a/packages/playgrodd-bundler-webpack/src/config-devserver.ts b/packages/playgrodd-bundler-webpack/src/config-devserver.ts index 15c5d2162..d0ad4c651 100644 --- a/packages/playgrodd-bundler-webpack/src/config-devserver.ts +++ b/packages/playgrodd-bundler-webpack/src/config-devserver.ts @@ -1,17 +1,14 @@ +import { ConfigArgs } from 'playgrodd-core' import { Application } from 'express' import * as errorOverlayMiddleware from 'react-dev-utils/errorOverlayMiddleware' export const PROTOCOL = process.env.HTTPS === 'true' ? 'https' : 'http' export const HOST = process.env.HOST || '0.0.0.0' -export interface IDevServerConfigParams { - paths: any -} - -export const devServerConfig = ({ paths }: IDevServerConfigParams) => ({ +export const devServerConfig = ({ paths }: ConfigArgs) => ({ compress: true, clientLogLevel: 'none', - contentBase: paths.PLAYGRODD, + contentBase: paths.playgrodd, watchContentBase: true, hot: true, quiet: true, diff --git a/packages/playgrodd-bundler-webpack/src/config.dev.ts b/packages/playgrodd-bundler-webpack/src/config.dev.ts index eff8d037c..aaf9cc3d0 100644 --- a/packages/playgrodd-bundler-webpack/src/config.dev.ts +++ b/packages/playgrodd-bundler-webpack/src/config.dev.ts @@ -4,75 +4,75 @@ import * as webpack from 'webpack' import * as HtmlWebpackPlugin from 'html-webpack-plugin' import * as webpackDevServerUtils from 'react-dev-utils/WebpackDevServerUtils' import * as WebpackDevServer from 'webpack-dev-server' -import { IBundlerFactoryParams as Args, Entry } from 'playgrodd-core' +import { ConfigArgs as Config, Entry } from 'playgrodd-core' import { devServerConfig } from './config-devserver' import * as loaders from './loaders' -const HOST = process.env.HOST || '0.0.0.0' - -export const config = ({ paths }: Args) => ( +export const config = ({ paths, host, src }: Config) => ( entries: Entry[] -): Configuration => ({ - mode: 'development', - context: paths.ROOT, - devtool: '#source-map', - entry: [ - require.resolve('babel-polyfill'), - require.resolve('react-dev-utils/webpackHotDevClient'), - paths.INDEX_JS, - ], - output: { - pathinfo: true, - path: paths.DIST, - publicPath: '/', - filename: 'static/js/[name].js', - sourceMapFilename: 'static/js/[name].js.map', - crossOriginLoading: 'anonymous', - devtoolModuleFilenameTemplate: (info: any) => - path.resolve(info.absoluteResourcePath).replace(/\\/g, '/'), - }, - module: { - rules: [ - { - oneOf: [ - { - test: /\.(js|jsx|mjs)$/, - exclude: /node_modules/, - include: [paths.ROOT], - use: [require.resolve('thread-loader'), loaders.babel], - }, - ], - }, +): Configuration => { + const srcPath = path.resolve(paths.root, src) + + return { + mode: 'development', + devtool: '#source-map', + context: paths.root, + entry: [ + require.resolve('babel-polyfill'), + require.resolve('react-dev-utils/webpackHotDevClient'), + paths.indexJs, ], - }, - resolve: { - extensions: ['.web.js', '.mjs', '.js', '.json', '.web.jsx', '.jsx'], - modules: [paths.ROOT, 'node_modules'], - alias: { - '@babel/runtime': path.dirname( - require.resolve('@babel/runtime/package.json') - ), + output: { + pathinfo: true, + path: paths.dist, + publicPath: '/', + filename: 'static/js/[name].js', + sourceMapFilename: 'static/js/[name].js.map', + crossOriginLoading: 'anonymous', + devtoolModuleFilenameTemplate: (info: any) => + path.resolve(info.absoluteResourcePath).replace(/\\/g, '/'), + }, + module: { + rules: [ + { + oneOf: [ + { + test: /\.(js|jsx|mjs)$/, + exclude: /node_modules/, + include: [srcPath, paths.playgrodd], + use: [require.resolve('thread-loader'), loaders.babel], + }, + ], + }, + ], }, - }, - devServer: { - logLevel: 'silent', - }, - plugins: [ - new webpack.NamedModulesPlugin(), - new webpack.HotModuleReplacementPlugin(), - new webpack.NoEmitOnErrorsPlugin(), - new HtmlWebpackPlugin({ - inject: true, - template: paths.INDEX_HTML, - }), - ], -}) + resolve: { + extensions: ['.web.js', '.mjs', '.js', '.json', '.web.jsx', '.jsx'], + modules: ['node_modules', srcPath], + alias: { + '@babel/runtime': path.dirname( + require.resolve('@babel/runtime/package.json') + ), + }, + }, + plugins: [ + new webpack.NamedModulesPlugin(), + new webpack.HotModuleReplacementPlugin(), + new webpack.NoEmitOnErrorsPlugin(), + new HtmlWebpackPlugin({ + inject: true, + template: paths.indexHtml, + }), + ], + } +} -export const setup = ({ paths, port }: Args) => (config: Configuration) => { - const appName = require(paths.PACKAGE_JSON).name - const protocol = process.env.HTTPS === 'true' ? 'https' : 'http' - const urls = webpackDevServerUtils.prepareUrls(protocol, HOST, port) +export const setup = ({ paths, port, host, protocol }: Config) => ( + config: Configuration +) => { + const appName = require(paths.packageJson).name + const urls = webpackDevServerUtils.prepareUrls(protocol, host, port) return webpackDevServerUtils.createCompiler( webpack, @@ -83,5 +83,5 @@ export const setup = ({ paths, port }: Args) => (config: Configuration) => { ) } -export const server = (args: Args) => (compiler: any): WebpackDevServer => - new WebpackDevServer(compiler, devServerConfig(args)) +export const server = (config: Config) => (compiler: any): WebpackDevServer => + new WebpackDevServer(compiler, devServerConfig(config)) diff --git a/packages/playgrodd-bundler-webpack/src/index.ts b/packages/playgrodd-bundler-webpack/src/index.ts index 9f14a2b34..9d6e1286a 100644 --- a/packages/playgrodd-bundler-webpack/src/index.ts +++ b/packages/playgrodd-bundler-webpack/src/index.ts @@ -1,13 +1,15 @@ -import { Bundler, IBundlerFactoryParams } from 'playgrodd-core' import { Configuration } from 'webpack' +import { createBundler, IBundlerCreate } from 'playgrodd-core' import * as WebpackDevServer from 'webpack-dev-server' import { config, setup, server } from './config.dev' -export const create = (params: IBundlerFactoryParams) => - new Bundler({ - id: 'webpack', - config: config(params), - server: server(params), - setup: setup(params), - }) +export const bundler: IBundlerCreate< + Configuration, + WebpackDevServer +> = createBundler({ + id: 'webpack', + config, + server, + setup, +}) diff --git a/packages/playgrodd-core/src/Bundler.ts b/packages/playgrodd-core/src/Bundler.ts index 3b611f1e1..2d23b02d1 100644 --- a/packages/playgrodd-core/src/Bundler.ts +++ b/packages/playgrodd-core/src/Bundler.ts @@ -5,6 +5,7 @@ import { compile } from 'art-template' import * as paths from './config/paths' import { Entry } from './Entry' +import { ConfigArgs } from './Server' const mkd = (dir: string): void => { try { @@ -15,18 +16,22 @@ const mkd = (dir: string): void => { } const touch = (file: string, content: string) => { - mkd(paths.PLAYGRODD) + mkd(paths.playgrodd) fs.writeFileSync(file, content, 'utf-8') } const compiled = (templateFile: string) => - compile(fs.readFileSync(`${paths.TEMPLATES_PATH}/${templateFile}`, 'utf-8')) + compile(fs.readFileSync(`${paths.templatesPath}/${templateFile}`, 'utf-8')) export type TConfigFn = (entries: Entry[]) => C export type TSetupFn = (config: C) => Promise export type TServerFn = (compiler: any) => S -export interface IConstructorParams { +export interface ICompilerOpts { + theme: string +} + +export interface IConstructorParams extends ICompilerOpts { id: string config: TConfigFn setup: TSetupFn @@ -39,24 +44,27 @@ const html = compiled('index.tpl.html') export class Bundler { readonly id: string + readonly theme: string private config: TConfigFn private setup: TSetupFn private server: TServerFn - constructor({ id, config, setup, server }: IConstructorParams) { + constructor({ id, config, theme, setup, server }: IConstructorParams) { this.id = id + this.theme = theme this.config = config this.setup = setup this.server = server } - public async createCompiler(theme: string, entries: Entry[]) { + public async createCompiler(entries: Entry[]) { + const { theme } = this const config = this.config(entries) - await del(paths.PLAYGRODD) - touch(paths.APP_JS, app({ theme, entries })) - touch(paths.INDEX_JS, js({})) - touch(paths.INDEX_HTML, html({})) + await del(paths.playgrodd) + touch(paths.appJs, app({ theme, entries })) + touch(paths.indexJs, js({})) + touch(paths.indexHtml, html({})) return await this.setup(config) } @@ -66,11 +74,26 @@ export class Bundler { } } -export interface IBundlerFactoryParams { - port: number - paths: paths.Paths +export interface IFactory { + id: string + config: (args: ConfigArgs) => TConfigFn + setup: (args: ConfigArgs) => TSetupFn + server: (args: ConfigArgs) => TServerFn +} + +export interface IBundlerCreate { + (args: ConfigArgs): Bundler } -export interface BundlerFactory { - create: (args: IBundlerFactoryParams) => Bundler +export function createBundler( + factory: IFactory +): IBundlerCreate { + return (args: ConfigArgs): Bundler => + new Bundler({ + id: factory.id, + theme: args.theme, + config: factory.config(args), + setup: factory.setup(args), + server: factory.server(args), + }) } diff --git a/packages/playgrodd-core/src/Entries.ts b/packages/playgrodd-core/src/Entries.ts index 5a81857c3..de1a8263e 100644 --- a/packages/playgrodd-core/src/Entries.ts +++ b/packages/playgrodd-core/src/Entries.ts @@ -37,7 +37,9 @@ export class Entries { ) } - public parse(): Entry[] { - return this.files.filter(isPlaygroddFile).map(file => new Entry(file)) + public parse(src: string): Entry[] { + return this.files + .filter(isPlaygroddFile) + .map(file => new Entry({ file, src })) } } diff --git a/packages/playgrodd-core/src/Entry.ts b/packages/playgrodd-core/src/Entry.ts index 6ca9dbb2b..121ba15f5 100644 --- a/packages/playgrodd-core/src/Entry.ts +++ b/packages/playgrodd-core/src/Entry.ts @@ -17,16 +17,22 @@ const getNameFromDoc = traverseAndAssign( path => path.node.arguments[0].value ) +export interface IConstructorParams { + file: string + src: string +} + export class Entry { public name: string public filepath: string public route: string - constructor(file: string) { + constructor({ src, file }: IConstructorParams) { const ast = convertToAst(file) const name = getNameFromDoc(ast) || '' const route = path.join('/', path.parse(file).dir, name) - const filepath = path.relative(paths.ROOT, file) + const source = path.relative(paths.root, src) + const filepath = path.relative(source, file) this.name = name this.route = route diff --git a/packages/playgrodd-core/src/config/paths.ts b/packages/playgrodd-core/src/config/paths.ts index c9ecfe69c..e95e1aae2 100644 --- a/packages/playgrodd-core/src/config/paths.ts +++ b/packages/playgrodd-core/src/config/paths.ts @@ -2,25 +2,23 @@ import * as fs from 'fs' import * as path from 'path' export type Paths = { - ROOT: string - PLAYGRODD: string - PACKAGE_JSON: string - - APP_JS: string - INDEX_JS: string - INDEX_HTML: string - DIST: string - - TEMPLATES_PATH: string + root: string + playgrodd: string + packageJson: string + appJs: string + indexJs: string + indexHtml: string + dist: string + templatesPath: string } -export const ROOT = fs.realpathSync(process.cwd()) -export const PLAYGRODD = path.join(ROOT, '.playgrodd') -export const PACKAGE_JSON = path.join(ROOT, 'package.json') +export const root = fs.realpathSync(process.cwd()) +export const playgrodd = path.resolve(root, '.playgrodd') +export const packageJson = path.resolve(root, 'package.json') -export const APP_JS = path.join(PLAYGRODD, 'app.jsx') -export const INDEX_JS = path.join(PLAYGRODD, 'index.jsx') -export const INDEX_HTML = path.join(PLAYGRODD, 'index.html') -export const DIST = path.join(PLAYGRODD, 'dist') +export const appJs = path.resolve(playgrodd, 'app.jsx') +export const indexJs = path.resolve(playgrodd, 'index.jsx') +export const indexHtml = path.resolve(playgrodd, 'index.html') +export const dist = path.resolve(playgrodd, 'dist/') -export const TEMPLATES_PATH = path.join(__dirname, '../../templates') +export const templatesPath = path.resolve(__dirname, '../../templates') diff --git a/packages/playgrodd-core/src/index.ts b/packages/playgrodd-core/src/index.ts index e38e19dc8..53974c5c1 100644 --- a/packages/playgrodd-core/src/index.ts +++ b/packages/playgrodd-core/src/index.ts @@ -1,5 +1,5 @@ export { Paths } from './config/Paths' -export { Server } from './server' export { Entry } from './Entry' -export { Bundler, IBundlerFactoryParams } from './Bundler' +export { createBundler, IBundlerCreate } from './Bundler' +export { Server, ConfigArgs } from './server' diff --git a/packages/playgrodd-core/src/server.ts b/packages/playgrodd-core/src/server.ts index 4238a87fd..829e6113a 100644 --- a/packages/playgrodd-core/src/server.ts +++ b/packages/playgrodd-core/src/server.ts @@ -4,39 +4,63 @@ import * as paths from './config/paths' import { pick } from './utils/helpers' import { Entries } from './Entries' -import { Bundler, BundlerFactory } from './Bundler' +import { Bundler } from './Bundler' process.env.BABEL_ENV = process.env.BABEL_ENV || 'development' process.env.NODE_ENV = process.env.NODE_ENV || 'development' +const ENV = process.env.NODE_ENV +const HOST = process.env.HOST || '0.0.0.0' +const PROTOCOL = process.env.HTTPS === 'true' ? 'https' : 'http' + +export interface ConfigArgs { + paths: any + port: number + theme: string + src: string + env: string + host: string + protocol: string +} + export interface IConstructorParams { port: number theme: string files: string bundler: string + src: string } export class Server { private port: number - private theme: string + private src: string private bundler: Bundler private entries: Entries constructor(args: IConstructorParams) { const initialArgs = this.getInitialArgs(args) - const { port, theme, files, bundler } = load('playgrodd', initialArgs) + const { port, theme, files, bundler, src } = load('playgrodd', initialArgs) this.port = port - this.theme = theme + this.src = src this.entries = new Entries(files) - this.bundler = this.getBundler(bundler).create({ port, paths }) + + this.bundler = this.getBundler(bundler).bundler({ + port, + paths, + theme, + src, + env: ENV, + host: HOST, + protocol: PROTOCOL, + }) } private getInitialArgs(args: IConstructorParams) { - return pick(['port', 'theme', 'files', 'bundler'], args) + return pick(['port', 'theme', 'files', 'bundler', 'src'], args) } - private getBundler(bundler: string): BundlerFactory { + private getBundler(bundler: string) { try { return require(`playgrodd-bundler-${bundler}`) } catch (err) { @@ -45,9 +69,10 @@ export class Server { } public async start() { - const entries = this.entries.parse() - const compiler = await this.bundler.createCompiler(this.theme, entries) - const server = await this.bundler.createServer(compiler) + const { entries, bundler } = this + + const compiler = await bundler.createCompiler(entries.parse(this.src)) + const server = await bundler.createServer(compiler) server.listen(this.port) } diff --git a/packages/playgrodd/bin/index.js b/packages/playgrodd/bin/index.js index 2c53b4bda..53e756bba 100755 --- a/packages/playgrodd/bin/index.js +++ b/packages/playgrodd/bin/index.js @@ -8,22 +8,32 @@ yargs 'start [files]', 'initialize the playground server', yargs => { + yargs.positional('source', { + alias: 'src', + type: 'string', + default: 'src/', + describe: 'source folder of your project', + }) yargs.positional('files', { type: 'string', default: '**/*.(js|jsx)', describe: 'files that you want to document', }) yargs.positional('port', { + alias: 'p', type: 'number', default: 3000, + describe: 'server port that you app will run', }) yargs.positional('theme', { type: 'string', default: 'playgrodd-theme-default', + describe: 'path of your custom theme', }) yargs.positional('bundler', { type: 'string', default: 'webpack', + describe: 'the id of the bundler you want to use', }) }, argv => new Server(argv).start()