fliphub-monorepo
Version:
the builder of builders
193 lines (173 loc) • 5.25 kB
JavaScript
const path = require('path')
const ChainedMap = require('./ChainedMap')
const ChainedSet = require('./ChainedSet')
const Resolve = require('./Resolve')
const ResolveLoader = require('./ResolveLoader')
const Output = require('./Output')
const DevServer = require('./DevServer')
const Plugin = require('./Plugin')
const Module = require('./Module')
const Performance = require('./Performance')
module.exports = class extends ChainedMap {
constructor() {
super()
this.devServer = new DevServer(this)
this.entryPoints = new ChainedMap(this)
this.module = new Module(this)
this.node = new ChainedMap(this)
this.output = new Output(this)
this.performance = new Performance(this)
this.plugins = new ChainedMap(this)
this.resolve = new Resolve(this)
this.resolveLoader = new ResolveLoader(this)
this.extend([
'amd',
'bail',
'cache',
'devtool',
'context',
'externals',
'loader',
'profile',
'recordsPath',
'recordsInputPath',
'recordsOutputPath',
'stats',
'target',
'watch',
'watchOptions'
])
}
entry(name) {
if (!this.entryPoints.has(name)) {
this.entryPoints.set(name, new ChainedSet(this))
}
return this.entryPoints.get(name)
}
plugin(name) {
if (!this.plugins.has(name)) {
this.plugins.set(name, new Plugin(this))
}
return this.plugins.get(name)
}
toConfig() {
const entryPoints = this.entryPoints.entries() || {}
return this.clean(Object.assign(this.entries() || {}, {
node: this.node.entries(),
output: this.output.entries(),
resolve: this.resolve.toConfig(),
resolveLoader: this.resolveLoader.toConfig(),
devServer: this.devServer.entries(),
module: this.module.toConfig(),
plugins: this.plugins.values().map(plugin => plugin.toConfig()),
entry: Object
.keys(entryPoints)
.reduce((acc, key) => Object.assign(acc, {[key]: entryPoints[key].values()}), {})
}))
}
merge(obj = {}) {
Object
.keys(obj)
.forEach(key => {
const value = obj[key]
switch (key) {
case 'node':
case 'resolve':
case 'resolveLoader':
case 'devServer':
case 'module': {
return this[key].merge(value)
}
/**
* @example:
*
* input:
* '/code/example/dist/[name].js'
*
* output:
* {
* path: '/code/example/dist',
* filename: '[name].js',
* }
*
*
*/
case 'output': {
if (typeof value === 'string') {
const filename = path.basename(value)
const dir = path.dirname(value)
const asObject = {
path: dir,
filename
}
return this.output.merge(asObject)
}
return this[key].merge(value)
}
/**
* take a string entry,
* file name becomes property,
* value becomes an array,
* if the same prop exists,
* it is merged in with existing values
*
* @example:
*
* input: './src/front/index.js'
* output: {index: ['./src/front/index.js']}
*/
case 'entry': {
if (typeof value === 'string') {
let name = path.basename(value)
if (name.includes('.')) {
name = name.split('.').shift()
}
let includes = false
// dedupe when we have relative then resolved
this.entryPoints.values().forEach(val => {
if (value.includes(value)) includes = true
})
if (includes) {
this.entryPoints = new ChainedMap(this)
return this.entry(name).merge([value])
} else {
return this.entry(name).merge([value])
}
}
return Object
.keys(value)
.forEach(name => this.entry(name).merge(value[name]))
}
case 'plugin': {
return Object
.keys(value)
.forEach(name => this.plugin(name).merge(value[name]))
}
/**
* @see ./Plugin
* merge an array of plugins
*/
case 'plugins': {
if (Array.isArray(value)) {
return value
.forEach((plugin, index) => {
plugin.name = plugin.name || index
// if Class, default Plugin.init will instantiate it
if (toString.call(plugin) === '[object Function]') {
this.plugin(plugin.name).plugin(plugin)
}
// otherwise, it is already instantiated
else {
this.plugin(plugin.name).init((args) => plugin)
}
})
}
}
default: {
this.set(key, value)
}
}
})
return this
}
}