-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(docz-core): split bundler logic
- Loading branch information
1 parent
7484267
commit a7db904
Showing
16 changed files
with
330 additions
and
287 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import * as fs from 'fs' | ||
import * as mkdir from 'mkdirp' | ||
import * as del from 'del' | ||
import { compile } from 'art-template' | ||
|
||
import * as paths from './config/paths' | ||
import { Entry } from './Entry' | ||
|
||
const mkd = (dir: string): void => { | ||
try { | ||
fs.lstatSync(dir) | ||
} catch (err) { | ||
mkdir.sync(dir) | ||
} | ||
} | ||
|
||
const touch = (file: string, content: string) => { | ||
mkd(paths.PLAYGRODD) | ||
fs.writeFileSync(file, content, 'utf-8') | ||
} | ||
|
||
const compiled = (templateFile: string) => | ||
compile(fs.readFileSync(`${paths.TEMPLATES_PATH}/${templateFile}`, 'utf-8')) | ||
|
||
type TConfigFn<C> = (entries: Entry[]) => C | ||
type TSetupFn<C> = (config: C) => Promise<any> | ||
type TServerFn<S> = (compiler: any) => S | ||
|
||
interface IConstructorParams<C, S> { | ||
id: string | ||
config: TConfigFn<C> | ||
setup: TSetupFn<C> | ||
server: TServerFn<S> | ||
} | ||
|
||
const app = compiled('app.tpl.js') | ||
const js = compiled('index.tpl.js') | ||
const html = compiled('index.tpl.html') | ||
|
||
export class Bundler<C = any, S = any> { | ||
readonly id: string | ||
private config: TConfigFn<C> | ||
private setup: TSetupFn<C> | ||
private server: TServerFn<S> | ||
|
||
constructor({ id, config, setup, server }: IConstructorParams<C, S>) { | ||
this.id = id | ||
this.config = config | ||
this.setup = setup | ||
this.server = server | ||
} | ||
|
||
public async createCompiler(entries: Entry[]) { | ||
const config = this.config(entries) | ||
|
||
await del(paths.PLAYGRODD) | ||
touch(paths.APP_JS, app({ entries })) | ||
touch(paths.INDEX_JS, js({})) | ||
touch(paths.INDEX_HTML, html({})) | ||
|
||
return await this.setup(config) | ||
} | ||
|
||
public async createServer(compiler: any): Promise<S> { | ||
return await this.server(compiler) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import * as glob from 'fast-glob' | ||
import * as t from 'babel-types' | ||
import { NodePath } from 'babel-traverse' | ||
|
||
import { traverseAndAssign } from './utils/traverse' | ||
import { Entry, convertToAst } from './Entry' | ||
|
||
const hasPlaygroddImported = (path: NodePath<any>): boolean => | ||
path.isImportDeclaration() && | ||
path.node && | ||
path.node.source && | ||
path.node.source.value === 'playgrodd' | ||
|
||
const hasDocFn = (path: NodePath<any>): boolean => | ||
path.node.specifiers && | ||
path.node.specifiers.some( | ||
(node: NodePath<any>) => | ||
t.isImportSpecifier(node) && node.imported.name === 'doc' | ||
) | ||
|
||
const checkIfImportPlaygrodd = traverseAndAssign<NodePath<t.Node>, boolean>( | ||
path => hasPlaygroddImported(path) && hasDocFn(path), | ||
path => true | ||
) | ||
|
||
const isPlaygroddFile = (entry: string) => | ||
checkIfImportPlaygrodd(convertToAst(entry)) | ||
|
||
export class Entries { | ||
private files: string[] | ||
|
||
constructor(pattern: string) { | ||
const ignoreGlob = '!node_modules' | ||
|
||
this.files = glob.sync( | ||
Array.isArray(pattern) ? [...pattern, ignoreGlob] : [pattern, ignoreGlob] | ||
) | ||
} | ||
|
||
public parse(): Entry[] { | ||
return this.files.filter(isPlaygroddFile).map(file => new Entry(file)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import * as fs from 'fs' | ||
import * as path from 'path' | ||
import * as t from 'babel-types' | ||
import { parse } from 'babylon' | ||
|
||
import * as paths from './config/paths' | ||
import { traverseAndAssign } from './utils/traverse' | ||
|
||
export const convertToAst = (entry: string): t.File => | ||
parse(fs.readFileSync(entry, 'utf-8'), { | ||
sourceType: 'module', | ||
plugins: ['jsx'], | ||
}) | ||
|
||
const getNameFromDoc = traverseAndAssign<any, string>( | ||
path => path.isCallExpression() && path.node.callee.name === 'doc', | ||
path => path.node.arguments[0].value | ||
) | ||
|
||
export class Entry { | ||
public name: string | ||
public filepath: string | ||
public route: string | ||
|
||
constructor(file: string) { | ||
const ast = convertToAst(file) | ||
const name = getNameFromDoc(ast) || '' | ||
const route = path.join('/', path.parse(file).dir, name) | ||
const filepath = path.relative(paths.ROOT, file) | ||
|
||
this.name = name | ||
this.route = route | ||
this.filepath = filepath | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { bundler as webpack } from './webpack' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
import * as errorOverlayMiddleware from 'react-dev-utils/errorOverlayMiddleware' | ||
import * as path from 'path' | ||
import { Application } from 'express' | ||
import { Loader, Configuration } from 'webpack' | ||
import * as webpack from 'webpack' | ||
import * as merge from 'deepmerge' | ||
import * as HtmlWebpackPlugin from 'html-webpack-plugin' | ||
import * as webpackDevServerUtils from 'react-dev-utils/WebpackDevServerUtils' | ||
import * as WebpackDevServer from 'webpack-dev-server' | ||
|
||
import { loadConfig } from '../utils/load-config' | ||
import * as paths from '../config/paths' | ||
|
||
import { Bundler } from '../Bundler' | ||
import { Entry } from '../Entry' | ||
|
||
export const PORT = 3000 | ||
export const PROTOCOL = process.env.HTTPS === 'true' ? 'https' : 'http' | ||
export const HOST = process.env.HOST || '0.0.0.0' | ||
|
||
const devServerConfig = () => ({ | ||
compress: true, | ||
clientLogLevel: 'none', | ||
contentBase: paths.PLAYGRODD, | ||
watchContentBase: true, | ||
hot: true, | ||
quiet: true, | ||
noInfo: true, | ||
publicPath: '/', | ||
https: PROTOCOL === 'https', | ||
host: HOST, | ||
overlay: false, | ||
watchOptions: { | ||
ignored: /node_modules/, | ||
}, | ||
stats: { | ||
colors: true, | ||
chunks: false, | ||
chunkModules: false, | ||
}, | ||
historyApiFallback: { | ||
disableDotRule: true, | ||
}, | ||
before(app: Application) { | ||
app.use(errorOverlayMiddleware()) | ||
}, | ||
}) | ||
|
||
const babelLoader = (): Loader => { | ||
const babelrc = loadConfig('babel', null) | ||
const options = merge(babelrc, { | ||
babelrc: false, | ||
cacheDirectory: true, | ||
presets: [ | ||
require.resolve('@babel/preset-env'), | ||
require.resolve('@babel/preset-react'), | ||
], | ||
plugins: [require.resolve('react-hot-loader/babel')], | ||
}) | ||
|
||
return { | ||
options, | ||
loader: require.resolve('babel-loader'), | ||
} | ||
} | ||
|
||
const 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: [ | ||
{ | ||
test: /\.(js|jsx)$/, | ||
exclude: /node_modules/, | ||
include: [paths.ROOT], | ||
use: babelLoader(), | ||
}, | ||
], | ||
}, | ||
resolve: { | ||
extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'], | ||
modules: [paths.ROOT, 'node_modules'], | ||
alias: { | ||
'@babel/runtime': path.dirname( | ||
require.resolve('@babel/runtime/package.json') | ||
), | ||
}, | ||
}, | ||
devServer: { | ||
logLevel: 'silent', | ||
}, | ||
plugins: [ | ||
new webpack.NamedModulesPlugin(), | ||
new webpack.HotModuleReplacementPlugin(), | ||
new webpack.NoEmitOnErrorsPlugin(), | ||
new HtmlWebpackPlugin({ | ||
inject: true, | ||
template: paths.INDEX_HTML, | ||
}), | ||
], | ||
}) | ||
|
||
const setup = (config: Configuration) => { | ||
const appName = require(paths.PACKAGE_JSON).name | ||
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http' | ||
const urls = webpackDevServerUtils.prepareUrls(protocol, HOST, PORT) | ||
|
||
return webpackDevServerUtils.createCompiler( | ||
webpack, | ||
config, | ||
appName, | ||
urls, | ||
true | ||
) | ||
} | ||
|
||
const server = (compiler: any): WebpackDevServer => | ||
new WebpackDevServer(compiler, devServerConfig()) | ||
|
||
export const bundler = (): Bundler => | ||
new Bundler<Configuration, WebpackDevServer>({ | ||
id: 'webpack', | ||
config, | ||
setup, | ||
server, | ||
}) |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.