Skip to content

Commit

Permalink
update resolve logic, add possibility to customise markdown plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
mightyaleksey committed Jul 31, 2021
1 parent b177841 commit d9da48a
Show file tree
Hide file tree
Showing 25 changed files with 386 additions and 343 deletions.
18 changes: 11 additions & 7 deletions lib/cmd-build.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ const fs = require('fs')
const path = require('path')
const { pipeline } = require('stream/promises')

const { FilemapWithOutput } = require('./core-filemap-with-output')
const { ListItem } = require('./core-data-structures')
const { Filemap } = require('./core-filemap-build')
const { Urlmap } = require('./core-urlmap')
const { ProcessingFactory } = require('./core-processing-factory')
const { ProcessingWithCache } = require('./core-processing-with-cache')
const { copy, mkdir } = require('./util-fs')
Expand Down Expand Up @@ -42,10 +44,12 @@ async function build (options, logger) {
const visited = new Set()

const plugins = loadCustomPlugins(settings.wave?.plugins, packageScope).concat(corePlugins)
const filemap = new FilemapWithOutput({ packageScope, wd })
const staticDirs = ListItem.from(publicDirectory)
const filemap = new Filemap({ packageScope, staticDirs, wd })
const urlmap = new Urlmap({ packageScope, staticDirs })
const cmd = 'build'

const factoryOptions = { plugins, filemap, cmd, env, settings, logger }
const factoryOptions = { plugins, filemap, urlmap, cmd, env, settings, logger }
if (options.cache) factoryOptions.product = ProcessingWithCache

const processingFactory = new ProcessingFactory(factoryOptions)
Expand All @@ -56,7 +60,7 @@ async function build (options, logger) {

const cwd = process.cwd()
for (const input of options._) {
const filepath = path.resolve(cwd, input)
const filepath = './' + path.relative(wd, path.resolve(cwd, input))
const processing = processingFactory.resolve(filepath, fakeReferer)
enqueue(processing)
}
Expand All @@ -68,9 +72,9 @@ async function build (options, logger) {
function enqueue (processing) {
if (processing == null) return

const publicUrl = processing.publicUrl()
if (visited.has(publicUrl)) return
visited.add(publicUrl)
const id = processing.id
if (visited.has(id)) return
visited.add(id)

q.push(processing)
}
Expand Down
100 changes: 35 additions & 65 deletions lib/cmd-serve.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
const chokidar = require('chokidar')
const fs = require('fs')
const path = require('path')
const { finished, pipeline } = require('stream')

const { FilemapWithAliases } = require('./core-filemap-with-aliases')
const { Filemap } = require('./core-filemap-serve')
const { ListItem } = require('./core-data-structures')
const { ProcessingFactory } = require('./core-processing-factory')
const { ProcessingWithCache } = require('./core-processing-with-cache')
const { UrlmapWithAliases } = require('./core-urlmap-with-aliases')
const { Urlmap } = require('./core-urlmap')
const { abc } = require('./util-hash')
const { broadcast, createSocket } = require('./util-socket')
const { contentType } = require('./util-mime-types')
Expand All @@ -18,6 +18,7 @@ const { debounce } = require('./util-scheduler')
const { isFile } = require('./util-fs')
const { loadCustomPlugins, loadPackageSettings } = require('./core-settings')
const { nodeModules } = require('./core-resolve')
const { pipe } = require('./util-stream')
const { scope } = require('./util-scope')

const corePlugins = [
Expand All @@ -37,7 +38,7 @@ async function serve (options, logger) {
const packageScope = await scope(wd) ?? wd
const settings = await loadPackageSettings(packageScope)
const publicDirectory = path.join(packageScope, 'public')
const innerPublicDirectory = path.resolve(__dirname, '../public')
const internalDirectory = path.resolve(__dirname, '../public')

logger.debug('environment variables %o', env)
logger.debug('package settings %o', settings)
Expand All @@ -52,14 +53,15 @@ async function serve (options, logger) {
const modulesDirs = nodeModules(path.dirname(packageScope))
if (modulesDirs != null) {
for (const directory of modulesDirs) {
const alias = `/~nm${abc(aliases.size)}`
const alias = `~nm${abc(aliases.size)}`
aliases.set(alias, directory)
}
}

const plugins = loadCustomPlugins(settings.wave?.plugins, packageScope).concat(corePlugins)
const filemap = new FilemapWithAliases({ aliases, packageScope, wd })
const urlmap = new UrlmapWithAliases({ aliases }); urlmap.cache = cache
const staticDirs = ListItem.from(publicDirectory)
const filemap = new Filemap({ aliases, packageScope, staticDirs, wd })
const urlmap = new Urlmap({ aliases, packageScope, staticDirs }); urlmap.cache = cache
const cmd = 'serve'

const factoryOptions = { plugins, filemap, urlmap, cmd, env, settings, logger }
Expand All @@ -70,15 +72,37 @@ async function serve (options, logger) {
async function middleware (req, res) {
const startTime = Date.now()

let url = new URL(req.url, `http://localhost:${port}/`).pathname
if (url.endsWith('/')) url += 'index.html'
const url = new URL(req.url, `http://localhost:${port}/`).pathname

if (req.method !== 'GET') {
res.writeHead(405, { allow: 'GET' })
res.end()
return
}

if (url.startsWith('/-internal-/')) {
const internalFile = path.join(internalDirectory, url.substring(12))
if (await isFile(internalFile)) {
res.writeHead(200, {
'content-type': contentType(internalFile),
'server-timing': [
'internalFile',
`routing;dur=${Date.now() - startTime}`
].join(', ')
})

pipe(fs.createReadStream(internalFile), res, err => {
if (err != null) handleRequestError(err, res)
})
} else {
// nothing to serve
res.writeHead(404, 'not found')
res.end()
}

return
}

// serve project files and apply transformation if necessary
const processing = processingFactory.resolve('.' + url, fakeReferer) // treat urls as relative paths
if (processing != null) {
Expand All @@ -90,67 +114,13 @@ async function serve (options, logger) {
].join(', ')
})

const streams = await processing.transform()
if (streams.length > 1) {
pipeline(
...streams,
err => {
if (err != null) handleRequestError(err, res)
}
).pipe(res)
} else {
finished(
streams[0].pipe(res),
err => {
if (err != null) handleRequestError(err, res)
}
)
}
return
}

// serve files from "public" directory
const publicFile = path.join(publicDirectory, url)
if (await isFile(publicFile)) {
res.writeHead(200, {
'content-type': contentType(publicFile),
'server-timing': [
'publicFile',
`routing;dur=${Date.now() - startTime}`
].join(', ')
pipe(await processing.transform(), res, err => {
if (err != null) handleRequestError(err, res)
})

finished(
fs.createReadStream(publicFile).pipe(res),
err => {
if (err != null) handleRequestError(err, res)
}
)
return
}

// serve development helpers from internal "public" directory
if (url.startsWith('/~/')) {
const innerFile = url.replace('/~', innerPublicDirectory)
if (await isFile(innerFile)) {
res.writeHead(200, {
'content-type': contentType(innerFile),
'server-timing': [
'internalFile',
`routing;dur=${Date.now() - startTime}`
].join(', ')
})

finished(
fs.createReadStream(innerFile).pipe(res),
err => {
if (err != null) handleRequestError(err, res)
}
)
return
}
}

// nothing to serve
res.writeHead(404, 'not found')
res.end()
Expand Down
44 changes: 44 additions & 0 deletions lib/core-filemap-build.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
'use strict'

const path = require('path')

const { IFilemap } = require('./core-filemap-i')
const { extname } = require('./util-path')
const { hash } = require('./util-hash')

class Filemap extends IFilemap {
constructor (options) {
super(options)

this.packageScope = options.packageScope
this.staticDirs = options.staticDirs
this.wd = options.wd
}

map (abspath, referer) {
super.map(abspath, referer)

if (this.staticDirs != null) {
for (const directory of this.staticDirs) {
if (abspath.startsWith(directory)) return '/' + path.relative(directory, abspath)
}
}

const ext = extname(abspath)
const genericName = hash(path.relative(this.packageScope, abspath))

switch (ext) {
case '.html':
return '/' + path.relative(this.wd, abspath)
case '.css':
case '.js':
return '/' + path.join('static', ext.substring(1), genericName + ext)
default:
return '/' + path.join('static', 'media', genericName + ext)
}
}
}

module.exports = {
Filemap
}
14 changes: 14 additions & 0 deletions lib/core-filemap-i.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
'use strict'

const assert = require('assert')

class IFilemap {
map (abspath, referer, options) {
assert(typeof abspath === 'string')
return null
}
}

module.exports = {
IFilemap
}
68 changes: 68 additions & 0 deletions lib/core-filemap-serve.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
'use strict'

const path = require('path')

const { IFilemap } = require('./core-filemap-i')
const { hash } = require('./util-hash')
const { foldLevels } = require('./util-path')

const workdir = Symbol('workdir')

class Filemap extends IFilemap {
constructor (options) {
super(options)

this.aliases = options.aliases
this.packageScope = options.packageScope
this.staticDirs = options.staticDirs
this.wd = options.wd

this[workdir] = path.relative(this.packageScope, this.wd)
}

map (abspath, referer) {
super.map(abspath, referer)

if (this.staticDirs != null) {
for (const directory of this.staticDirs) {
if (abspath.startsWith(directory)) return '/' + path.relative(directory, abspath)
}
}

const relative = path.relative(this.packageScope, abspath)

if (relative.startsWith(this[workdir])) {
return '/' + path.relative(this[workdir], relative)
}

if (relative.startsWith('../')) {
if (relative.includes('node_modules')) {
const base = abspath.substring(0, abspath.indexOf('node_modules') + 'node_modules'.length)
for (const [alias, directory] of this.aliases) {
if (base === directory) return '/' + path.join(alias, abspath.substring(base.length + 1))
}
}

return null
}

const right = foldLevels(path.relative(this[workdir], relative))
const middle = relative.substring(0, relative.lastIndexOf(right))

const alias = `~${hash(middle)}` // todo a readable solution
if (!this.aliases.has(alias)) {
const base = path.join(this.packageScope, middle.substring(0, middle.length - path.sep.length))
this.aliases.set(alias, base)
}

return '/' + path.join(alias, right)
}

output (relative) {
return relative
}
}

module.exports = {
Filemap
}
52 changes: 0 additions & 52 deletions lib/core-filemap-with-aliases.js

This file was deleted.

Loading

0 comments on commit d9da48a

Please sign in to comment.