Skip to content

Commit

Permalink
refactor(ts): convert layouts plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
egoist committed Nov 2, 2019
1 parent 321147c commit 3768f5c
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 139 deletions.
51 changes: 25 additions & 26 deletions packages/saber/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ export class Saber {
}
configDir?: string
configPath?: string
theme?: string
theme: string
actualServerPort?: number

constructor(opts: SaberConstructorOptions = {}, config: SaberConfig = {}) {
Expand Down Expand Up @@ -299,8 +299,6 @@ export class Saber {
this.configDir = ''
this.configPath = ''

this.renderer = new VueRenderer()

// Load Saber config
const loadedConfig = this.loadConfig()
this.config = loadedConfig.config
Expand All @@ -313,6 +311,30 @@ export class Saber {
)}`
)
}

this.renderer = new VueRenderer()
this.renderer.init(this)

// Load theme
if (this.config.theme) {
this.theme = resolvePackage(this.config.theme, {
cwd: this.configDir || this.opts.cwd,
prefix: 'saber-theme-'
})
// When a theme is loaded from `node_modules` and `$theme/dist` directory exists
// We use the `dist` directory instead
if (this.theme.includes('node_modules')) {
const distDir = path.join(this.theme, 'dist')
if (fs.existsSync(distDir)) {
this.theme = distDir
}
}

log.info(`Using theme: ${colors.dim(this.config.theme)}`)
log.verbose(() => `Theme directory: ${colors.dim(this.theme)}`)
} else {
this.theme = this.renderer.defaultTheme
}
}

loadConfig(configFiles = configLoader.CONFIG_FILES) {
Expand Down Expand Up @@ -343,29 +365,6 @@ export class Saber {
}

async prepare() {
this.renderer.init(this)

// Load theme
if (this.config.theme) {
this.theme = resolvePackage(this.config.theme, {
cwd: this.configDir || this.opts.cwd,
prefix: 'saber-theme-'
})
// When a theme is loaded from `node_modules` and `$theme/dist` directory exists
// We use the `dist` directory instead
if (this.theme.includes('node_modules')) {
const distDir = path.join(this.theme, 'dist')
if (fs.existsSync(distDir)) {
this.theme = distDir
}
}

log.info(`Using theme: ${colors.dim(this.config.theme)}`)
log.verbose(() => `Theme directory: ${colors.dim(this.theme)}`)
} else {
this.theme = this.renderer.defaultTheme
}

// Load built-in plugins
for (const plugin of builtinPlugins) {
const resolvedPlugin = require(plugin.resolve)
Expand Down
113 changes: 0 additions & 113 deletions packages/saber/src/plugins/layouts.js

This file was deleted.

131 changes: 131 additions & 0 deletions packages/saber/src/plugins/layouts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import path from 'path'
import { glob, fs, slash } from 'saber-utils'
import { SaberPlugin } from '..'

interface Layouts {
[name: string]: string
}

const ID = 'builtin:layouts'

const layoutsPlugin: SaberPlugin = {
name: ID,

apply(api) {
const setLayout = (
layouts: Layouts,
filepath: string,
shouldDelete?: boolean
) => {
const layoutName = path.basename(filepath, path.extname(filepath))
if (shouldDelete) {
delete layouts[layoutName]
} else {
layouts[layoutName] = slash(filepath)
}
}

const getLayouts = async (dir: string) => {
const files = await glob('*.{vue,js}', {
cwd: dir
})
const layouts = {}
files.forEach(file => {
setLayout(layouts, path.join(dir, file as string))
})
return layouts
}

const writeLayouts = async (
themeLayouts: Layouts,
userLayouts: Layouts
) => {
const layouts = Object.assign({}, themeLayouts, userLayouts)

api.log.verbose(() => `Found layouts: ${Object.keys(layouts).join(', ')}`)

const outFile = api.resolveCache('layouts.js')
const outContent = `var layouts = {}
${Object.keys(layouts)
.map((name, index) => {
return `
import layout_${index} from "${layouts[name]}"
layouts["${name}"] = layout_${index}
`
})
.join('\n')}
export default layouts`
await fs.outputFile(outFile, outContent, 'utf8')
}

api.hooks.beforeRun.tapPromise(ID, async () => {
const themeLayoutsDir = path.join(api.theme, 'layouts')
const userLayoutsDir = api.resolveCwd('layouts')
const [themeLayouts, userLayouts] = await Promise.all([
getLayouts(themeLayoutsDir),
getLayouts(userLayoutsDir)
])
await writeLayouts(themeLayouts, userLayouts)

if (api.dev) {
const watchLayouts = (dir: string, layouts: Layouts) => {
const chokidar = require('chokidar')

const onRemoveDir = async (dir: string) => {
if (!dir) {
Object.keys(layouts).forEach(name => {
delete layouts[name]
})
await writeLayouts(themeLayouts, userLayouts)
}
}

const onAddLayout = async (file: string) => {
setLayout(layouts, path.join(dir, file))
await writeLayouts(themeLayouts, userLayouts)
}

const onRemoveLayout = async (file: string) => {
setLayout(layouts, path.join(dir, file), true)
await writeLayouts(themeLayouts, userLayouts)
}

// Clear the layouts object when the layouts directory is removed
chokidar
.watch('.', {
cwd: dir,
disableGlobbing: true,
ignored(filepath: string) {
return filepath !== dir
},
ignoreInitial: true
})
.on('unlinkDir', (dir: string) => {
onRemoveDir(dir)
})

// Add/Remove layout components
chokidar
.watch('*.{vue,js}', { cwd: dir, ignoreInitial: true })
.on('add', (file: string) => {
onAddLayout(file)
})
.on('unlink', (file: string) => {
onRemoveLayout(file)
})
}

// No need to watch theme layouts if it's from an npm package
if (!themeLayoutsDir.includes('node_modules')) {
watchLayouts(themeLayoutsDir, themeLayouts)
}

watchLayouts(userLayoutsDir, userLayouts)
}
})
}
}

export default layoutsPlugin

0 comments on commit 3768f5c

Please sign in to comment.