chore: wip

This commit is contained in:
Sébastien Chopin 2020-08-17 20:02:10 +02:00
parent daaa8eda8c
commit dc84429d67
6 changed files with 143 additions and 32 deletions

View File

@ -1,4 +1,5 @@
import { resolve } from 'path' import { resolve } from 'path'
import { createWatcher } from './watch'
export interface NuxtRoute { export interface NuxtRoute {
path: '' path: ''

View File

@ -1,11 +1,15 @@
import { join } from 'path'
import fsExtra from 'fs-extra'
import { BundleBuilder } from 'src/webpack' import { BundleBuilder } from 'src/webpack'
import { Nuxt } from '../core' import { Nuxt } from '../core'
import { copyTemplates } from './template' import { compileTemplates, scanTemplates, NuxtTemplate } from './template'
import { createWatcher } from './watch'
import { resolveApp, NuxtApp } from './app' import { resolveApp, NuxtApp } from './app'
export class Builder { export class Builder {
nuxt: Nuxt nuxt: Nuxt
app: NuxtApp app: NuxtApp
templates: NuxtTemplate[]
constructor (nuxt) { constructor (nuxt) {
this.nuxt = nuxt this.nuxt = nuxt
@ -20,12 +24,61 @@ export class Builder {
async function build(builder: Builder) { async function build(builder: Builder) {
const { nuxt } = builder const { nuxt } = builder
builder.app = resolveApp(nuxt, nuxt.options.srcDir) await generate(builder)
await copyTemplates(builder)
if (nuxt.options.dev) {
watch(builder)
}
await bundle(builder) await bundle(builder)
} }
function watch(builder: Builder) {
const { nuxt } = builder
// Watch internal templates
const nuxtAppWatcher = createWatcher(nuxt.options.appDir)
// nuxtAppWatcher.debug()
nuxtAppWatcher.watchAll(async () => {
console.log('Re-generate templates')
await compileTemplates(builder.templates, nuxt.options.buildDir)
})
// Watch user app
const appWatcher = createWatcher(builder.app.srcDir, {
ignored: [
nuxt.options.buildDir
]
})
// appWatcher.debug()
appWatcher.watch(/(A|a)pp\.[a-z]{2,3}/, async () => {
await new Promise((resolve) => setTimeout(resolve, 200))
await generate(builder)
})
appWatcher.watch('pages/', async () => {
console.log('Re-generate routes')
await compileTemplates(builder.templates, nuxt.options.buildDir)
})
}
export async function generate(builder: Builder) {
const { nuxt } = builder
await fsExtra.mkdirp(nuxt.options.buildDir)
builder.app = resolveApp(nuxt, nuxt.options.srcDir)
const templatesDir = join(builder.nuxt.options.appDir, '_templates')
const appTemplates = await scanTemplates(templatesDir, {
app: builder.app
})
builder.templates = [
...appTemplates
]
await compileTemplates(builder.templates, nuxt.options.buildDir)
}
async function bundle ({ nuxt }: Builder) { async function bundle ({ nuxt }: Builder) {
// TODO: get rid of this context and directly pass nuxt to BundleBuilder // TODO: get rid of this context and directly pass nuxt to BundleBuilder
const bundleBuilder = new BundleBuilder({ const bundleBuilder = new BundleBuilder({

View File

@ -1,26 +1,40 @@
import { resolve, join, sep } from 'path' import { join, relative, dirname } from 'path'
import fsExtra from 'fs-extra' import fsExtra from 'fs-extra'
import globby from 'globby' import globby from 'globby'
import lodashTemplate from 'lodash/template' import lodashTemplate from 'lodash/template'
import { Builder } from './builder'
export async function copyTemplates ({ nuxt, app }: Builder) { interface NuxtTemplate {
// Resolve appDir src: string // Absolute path to source file
const templatesDir = join(nuxt.options.appDir, '_templates') path: string // Relative path of destination
data?: any
}
const templateFiles = (await globby(join(templatesDir, '/**'))) async function compileTemplate({ src, path, data }: NuxtTemplate, destDir: string) {
.map(f => f.replace(templatesDir + sep, ''))
await fsExtra.mkdirp(nuxt.options.buildDir)
for (const template of templateFiles) {
const src = resolve(templatesDir, template)
const dst = resolve(nuxt.options.buildDir, template)
const templateData = { app: Object.freeze(app) }
const srcContents = await fsExtra.readFile(src, 'utf-8') const srcContents = await fsExtra.readFile(src, 'utf-8')
const compiledSrc = lodashTemplate(srcContents, {})(templateData) const compiledSrc = lodashTemplate(srcContents, {})(data)
const dest = join(destDir, path)
console.log('Compile template', dest)
await fsExtra.mkdirp(dirname(dest))
await fsExtra.writeFile(dest, compiledSrc)
}
await fsExtra.writeFile(dst, compiledSrc) export async function compileTemplates(templates: NuxtTemplate[], destDir: string) {
return Promise.all(templates.map(t => compileTemplate(t, destDir)))
} }
export async function scanTemplates (dir: string, data?: Object) {
const templateFiles = (await globby(join(dir, '/**')))
return templateFiles.map(src => ({
src,
path: relative(dir, src),
data
}))
}
export async function watchTemplate(template: NuxtTemplate, watcher: any, cb: Function) {
template.data = new Proxy(template.data, {
// TODO: deep watch option changes
})
// TODO: Watch fs changes
} }

View File

@ -0,0 +1,40 @@
import chokidar, { WatchOptions } from 'chokidar'
import { relative } from 'path'
export function createWatcher(dir: string|string[], options?: WatchOptions) {
const watcher = chokidar.watch(dir, {
ignored: [],
ignoreInitial: true,
...options
})
const watchAll = (cb: Function, filter?: Function) => {
watcher.on('raw', (event, path: string, details) => {
if (options.ignored.find(ignore => path.match(ignore))) {
return // 🖕 chokidar ignored option
}
path = relative(dir, path)
const _event = { event, path }
if (!filter || filter(_event)) {
cb(_event)
}
})
}
const watch = (pattern: string| RegExp, cb: Function) => watchAll(cb, e => e.path.match(pattern))
const debug = (tag: string = '[Watcher]') => {
console.log(tag, 'Watching ', dir)
watchAll((e) => {
console.log(tag, e.event, e.path)
})
}
return {
watchAll,
watch,
debug
}
}
export type Watcher = ReturnType<typeof createWatcher>

View File

@ -4,7 +4,8 @@ import TimeFixPlugin from 'time-fix-plugin'
import cloneDeep from 'lodash/cloneDeep' import cloneDeep from 'lodash/cloneDeep'
import escapeRegExp from 'lodash/escapeRegExp' import escapeRegExp from 'lodash/escapeRegExp'
import VueLoaderPlugin from 'vue-loader/dist/pluginWebpack5' import VueLoaderPlugin from 'vue-loader/dist/pluginWebpack5'
import ExtractCssChunksPlugin from 'extract-css-chunks-webpack-plugin' // import ExtractCssChunksPlugin from 'extract-css-chunks-webpack-plugin'
import MiniCssExtractPlugin from 'mini-css-extract-plugin'
import TerserWebpackPlugin from 'terser-webpack-plugin' import TerserWebpackPlugin from 'terser-webpack-plugin'
import WebpackBar from 'webpackbar' import WebpackBar from 'webpackbar'
import env from 'std-env' import env from 'std-env'
@ -398,7 +399,7 @@ export default class WebpackBaseConfig {
// CSS extraction) // CSS extraction)
if (buildOptions.extractCSS) { if (buildOptions.extractCSS) {
plugins.push(new ExtractCssChunksPlugin(Object.assign({ plugins.push(new MiniCssExtractPlugin(Object.assign({
filename: this.getFileName('css'), filename: this.getFileName('css'),
chunkFilename: this.getFileName('css') chunkFilename: this.getFileName('css')
}, buildOptions.extractCSS))) }, buildOptions.extractCSS)))
@ -446,7 +447,7 @@ export default class WebpackBaseConfig {
// CSS extraction // CSS extraction
if (this.buildContext.buildOptions.extractCSS) { if (this.buildContext.buildOptions.extractCSS) {
plugins.push(new ExtractCssChunksPlugin(Object.assign({ plugins.push(new MiniCssExtractPlugin(Object.assign({
filename: this.getFileName('css'), filename: this.getFileName('css'),
chunkFilename: this.getFileName('css'), chunkFilename: this.getFileName('css'),
// TODO: https://github.com/faceyspacey/extract-css-chunks-webpack-plugin/issues/132 // TODO: https://github.com/faceyspacey/extract-css-chunks-webpack-plugin/issues/132

View File

@ -1,5 +1,6 @@
import path from 'path' import path from 'path'
import ExtractCssChunksPlugin from 'extract-css-chunks-webpack-plugin' // import ExtractCssChunksPlugin from 'extract-css-chunks-webpack-plugin'
import MiniCssExtractPlugin from 'mini-css-extract-plugin'
import { wrapArray } from 'src/utils' import { wrapArray } from 'src/utils'
@ -21,7 +22,8 @@ export default class StyleLoader {
} }
get onlyLocals() { get onlyLocals() {
return Boolean(this.isServer && this.extractCSS) // Not supported anymore by css-loader
return false // Boolean(this.isServer && this.extractCSS)
} }
normalize (loaders) { normalize (loaders) {
@ -86,7 +88,7 @@ export default class StyleLoader {
if (this.extractCSS) { if (this.extractCSS) {
const isDev = this.buildContext.options.dev const isDev = this.buildContext.options.dev
return { return {
loader: ExtractCssChunksPlugin.loader, loader: MiniCssExtractPlugin.loader,
options: { options: {
// TODO: https://github.com/faceyspacey/extract-css-chunks-webpack-plugin/issues/132 // TODO: https://github.com/faceyspacey/extract-css-chunks-webpack-plugin/issues/132
// https://github.com/faceyspacey/extract-css-chunks-webpack-plugin/issues/161#issuecomment-500162574 // https://github.com/faceyspacey/extract-css-chunks-webpack-plugin/issues/161#issuecomment-500162574