Skip to content

Commit

Permalink
feat: transform vue template with posthtml (#479)
Browse files Browse the repository at this point in the history
* use posthtml

* remove legacy test

* add test

* use custom path

* add hook transformTemplate

* Replace hook transformTemplate with chainTemplate

* fix hook type

* fix

* tweaks
  • Loading branch information
egoist authored Sep 27, 2019
1 parent fb28324 commit b56296a
Show file tree
Hide file tree
Showing 19 changed files with 289 additions and 124 deletions.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/

const ChainedMap = require('webpack-chain/src/ChainedMap')
const resolvePackage = require('../utils/resolvePackage')
const Plugin = require('./Plugin')
const Options = require('./Options')

Expand All @@ -29,4 +30,25 @@ module.exports = class MarkdownItChain extends ChainedMap {

return this.plugins.get(name)
}

loadPlugins(rawPluginList, cwd) {
const pluginList = rawPluginList.map(plugin => {
if (typeof plugin === 'string') {
plugin = { resolve: plugin }
}

plugin.resolve = resolvePackage(plugin.resolve, { cwd })
plugin.name = plugin.name || plugin.resolve
plugin.handler = require(plugin.resolve)

return plugin
})

for (const plugin of pluginList) {
this.plugin(plugin.name).use(
plugin.handler,
Array.isArray(plugin.options) ? plugin.options : [plugin.options]
)
}
}
}
1 change: 1 addition & 0 deletions packages/saber/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class Saber {
getWebpackConfig: new SyncWaterfallHook(['config', 'opts']),
// Extend markdown-it config
chainMarkdown: new SyncHook(['config']),
chainTemplate: new SyncHook(['config']),
emitRoutes: new AsyncSeriesHook(),
// Called after running webpack
afterBuild: new AsyncSeriesHook(),
Expand Down
22 changes: 0 additions & 22 deletions packages/saber/lib/markdown/__test__/link-plugin.test.js

This file was deleted.

67 changes: 0 additions & 67 deletions packages/saber/lib/markdown/link-plugin.js

This file was deleted.

40 changes: 11 additions & 29 deletions packages/saber/lib/plugins/transformer-markdown.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const MarkdownChain = require('../markdown-chain')
const ConfigChain = require('../config-chain')
const resolvePackage = require('../utils/resolvePackage')

exports.name = 'builtin:transformer-markdown'
Expand Down Expand Up @@ -39,7 +39,7 @@ function transformMarkdown(api, page) {
page
}

const chain = new MarkdownChain()
const chain = new ConfigChain()

chain.options.merge(
Object.assign(
Expand All @@ -52,7 +52,7 @@ function transformMarkdown(api, page) {
)
)

const pluginList = [
const builtInPlugins = [
{
name: 'hoist-tags',
resolve: require.resolve('../markdown/hoist-tags-plugin')
Expand Down Expand Up @@ -82,40 +82,22 @@ function transformMarkdown(api, page) {
lineNumbers: markdown.lineNumbers
}
},
{
name: 'link',
resolve: require.resolve('../markdown/link-plugin')
},
{
name: 'task-list',
resolve: require.resolve('../markdown/task-list-plugin')
},
...(markdown.plugins
? markdown.plugins.map(p => {
if (typeof p === 'string') {
p = { resolve: p }
}

p.name = p.name || p.resolve
p.resolve = resolvePackage(p.resolve, { cwd: configDir })
return p
})
: [])
}
]

for (const plugin of pluginList) {
chain
.plugin(plugin.name)
.use(
typeof plugin.resolve === 'string'
? require(plugin.resolve)
: plugin.resolve,
Array.isArray(plugin.options) ? plugin.options : [plugin.options]
)
}
// Load built-in plugins
chain.loadPlugins(builtInPlugins, configDir)

api.hooks.chainMarkdown.call(chain)

// Load plugins from config file
if (markdown.plugins) {
chain.loadPlugins(markdown.plugins, configDir)
}

const { options, plugins } = chain.toConfig()

if (typeof options.highlight === 'string') {
Expand Down
1 change: 1 addition & 0 deletions packages/saber/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"object-assign": "^4.1.1",
"open": "^6.4.0",
"polka": "^0.5.1",
"posthtml": "^0.11.6",
"prettier": "^1.17.0",
"pretty-ms": "^5.0.0",
"resolve-from": "^5.0.0",
Expand Down
7 changes: 6 additions & 1 deletion packages/saber/vue-renderer/app/create-app.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import './polyfills'
import '#cache/runtime-polyfills'
import { join, dirname } from 'path'
import Vue from 'vue'
import Meta from 'vue-meta'
import layouts from '#cache/layouts'
import createRouter from './router'
import Layout from './components/LayoutManager.vue'
import ClientOnly from './components/ClientOnly'
import extendBrowserApi from '#cache/extend-browser-api'
import { join, dirname } from './helpers/path'
import injectConfig from './helpers/inject-config'
import setTransition from './helpers/set-transition'
import scrollHandler from './helpers/scroll-handler'
Expand Down Expand Up @@ -125,6 +125,11 @@ export default context => {
const matched = Array.isArray(link)
? link // The link is already parsed
: /^([^#?]+)([#?].*)?$/.exec(link)

if (!matched) {
return link
}

const relativePath = join(
dirname(this.$route.meta.__relative),
matched[1]
Expand Down
86 changes: 86 additions & 0 deletions packages/saber/vue-renderer/app/helpers/path.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// eslint-disable
// Extracted from https://github.com/calvinmetcalf/rollup-plugin-node-builtins/blob/master/src/es6/path.js

function normalizeArray(parts, allowAboveRoot) {
// if the path tries to go above the root, `up` ends up > 0
var up = 0
for (var i = parts.length - 1; i >= 0; i--) {
var last = parts[i]
if (last === '.') {
parts.splice(i, 1)
} else if (last === '..') {
parts.splice(i, 1)
up++
} else if (up) {
parts.splice(i, 1)
up--
}
}

// if the path is allowed to go above the root, restore leading ..s
if (allowAboveRoot) {
for (; up--; up) {
parts.unshift('..')
}
}

return parts
}

// Split a filename into [root, dir, basename, ext], unix version
// 'root' is just a slash, or nothing.
var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/
var splitPath = function(filename) {
return splitPathRe.exec(filename).slice(1)
}

// path.normalize(path)
// posix version
function normalize(path) {
var isPathAbsolute = isAbsolute(path),
trailingSlash = path.substr(-1) === '/'

// Normalize the path
path = normalizeArray(
path.split('/').filter(Boolean),
!isPathAbsolute
).join('/')

if (!path && !isPathAbsolute) {
path = '.'
}
if (path && trailingSlash) {
path += '/'
}

return (isPathAbsolute ? '/' : '') + path
}
// posix version
function isAbsolute(path) {
return path.charAt(0) === '/'
}

// posix version
function join(...paths) {
return normalize(paths.filter(p => typeof p === 'string').join('/'))
}

function dirname(path) {
var result = splitPath(path),
root = result[0],
dir = result[1]

if (!root && !dir) {
// No dirname whatsoever
return '.'
}

if (dir) {
// It has a dirname, strip trailing slash
dir = dir.substr(0, dir.length - 1)
}

return root + dir
}

export { dirname, join }
9 changes: 9 additions & 0 deletions packages/saber/vue-renderer/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,15 @@ class VueRenderer {
getPagePublicFields: api.pages.getPagePublicFields.bind(api.pages)
}

config.module
.rule('transform-template')
.resourceQuery(/\?vue&type=template/)
.use('transform-template-loader')
.loader(require.resolve('./transform-template-loader'))
.options({
plugins: require('./template-plugins')(api)
})

// Add `saber-page` rule under `js` rule to handle .js pages
// prettier-ignore
config.module
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const posthtml = require('posthtml')
const plugin = require('../link')

const transform = source =>
posthtml([plugin()])
.process(source, {
recognizeSelfClosing: true
})
.then(res => res.html)

test('basic', async () => {
const html = await transform(`
<a href="foo">foo</a>
<a href="https://example.com">foo</a>
<a href="mailto:[email protected]">foo</a>
<saber-link to="/foo">foo</saber-link>
<saber-link :to="foo">foo</saber-link>
`)
expect(html).toBe(`
<saber-link :to="$saber.getPageLink('foo')">foo</saber-link>
<a target="_blank" rel="noopener noreferrer" href="https://example.com">foo</a>
<a href="mailto:[email protected]">foo</a>
<saber-link :to="$saber.getPageLink('/foo')">foo</saber-link>
<saber-link :to="foo">foo</saber-link>
`)
})

test('ignore', async () => {
const html = await transform(`<a href="foo" saber-ignore>foo</a>`)
expect(html).toBe(`<a href="foo">foo</a>`)
})
Loading

0 comments on commit b56296a

Please sign in to comment.