@vituum/vite-plugin-pug 0.1.5 → 1.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +97 -88
- package/package.json +21 -8
- package/types/index.d.ts +37 -0
package/index.js
CHANGED
|
@@ -1,138 +1,147 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolve, relative } from 'path'
|
|
2
2
|
import fs from 'fs'
|
|
3
3
|
import process from 'node:process'
|
|
4
|
-
import FastGlob from 'fast-glob'
|
|
5
4
|
import lodash from 'lodash'
|
|
6
5
|
import pug from 'pug'
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
6
|
+
import { getPackageInfo, merge, pluginBundle, pluginError, pluginReload, processData } from 'vituum/utils/common.js'
|
|
7
|
+
import { renameBuildEnd, renameBuildStart } from 'vituum/utils/build.js'
|
|
8
|
+
import { minimatch } from 'minimatch'
|
|
9
9
|
|
|
10
|
-
const { name } =
|
|
10
|
+
const { name } = getPackageInfo(import.meta.url)
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @type {import('@vituum/vite-plugin-pug/types').PluginUserConfig}
|
|
14
|
+
*/
|
|
11
15
|
const defaultOptions = {
|
|
12
16
|
reload: true,
|
|
13
17
|
root: null,
|
|
14
18
|
filters: {},
|
|
15
|
-
globals: {
|
|
16
|
-
|
|
17
|
-
filetypes: {
|
|
18
|
-
html: /.(json.html|pug.json.html|pug.html)$/,
|
|
19
|
-
json: /.(json.pug.html)$/
|
|
19
|
+
globals: {
|
|
20
|
+
format: 'pug'
|
|
20
21
|
},
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
function processData(paths, data = {}) {
|
|
25
|
-
let context = {}
|
|
26
|
-
|
|
27
|
-
lodash.merge(context, data)
|
|
28
|
-
|
|
29
|
-
const normalizePaths = Array.isArray(paths) ? paths.map(path => path.replace(/\\/g, '/')) : paths.replace(/\\/g, '/')
|
|
30
|
-
|
|
31
|
-
FastGlob.sync(normalizePaths).forEach(entry => {
|
|
32
|
-
const path = resolve(process.cwd(), entry)
|
|
33
|
-
|
|
34
|
-
context = lodash.merge(context, JSON.parse(fs.readFileSync(path).toString()))
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
return context
|
|
22
|
+
data: ['src/data/**/*.json'],
|
|
23
|
+
formats: ['pug', 'json.pug', 'json'],
|
|
24
|
+
options: {}
|
|
38
25
|
}
|
|
39
26
|
|
|
40
|
-
const renderTemplate = async(filename, content, options) => {
|
|
27
|
+
const renderTemplate = async ({ filename, server, root }, content, options) => {
|
|
28
|
+
const initialFilename = filename.replace('.html', '')
|
|
41
29
|
const output = {}
|
|
42
|
-
const context = options.data
|
|
30
|
+
const context = options.data
|
|
31
|
+
? processData({
|
|
32
|
+
paths: options.data,
|
|
33
|
+
root
|
|
34
|
+
}, options.globals)
|
|
35
|
+
: options.globals
|
|
43
36
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (isJson || isHtml) {
|
|
48
|
-
lodash.merge(context, isHtml ? content : JSON.parse(fs.readFileSync(filename).toString()))
|
|
37
|
+
if (initialFilename.endsWith('.json')) {
|
|
38
|
+
lodash.merge(context, JSON.parse(content))
|
|
49
39
|
|
|
50
40
|
output.template = true
|
|
51
41
|
|
|
52
42
|
if (typeof context.template === 'undefined') {
|
|
53
|
-
|
|
43
|
+
const error = `${name}: template must be defined for file ${initialFilename}`
|
|
44
|
+
|
|
45
|
+
return new Promise((resolve) => {
|
|
46
|
+
output.error = error
|
|
47
|
+
resolve(output)
|
|
48
|
+
})
|
|
54
49
|
}
|
|
55
50
|
|
|
56
51
|
context.template = relative(process.cwd(), context.template).startsWith(relative(process.cwd(), options.root)) ? resolve(process.cwd(), context.template) : resolve(options.root, context.template)
|
|
57
|
-
} else if (fs.existsSync(
|
|
58
|
-
lodash.merge(context, JSON.parse(fs.readFileSync(
|
|
52
|
+
} else if (fs.existsSync(`${initialFilename}.json`)) {
|
|
53
|
+
lodash.merge(context, JSON.parse(fs.readFileSync(`${initialFilename}.json`).toString()))
|
|
59
54
|
}
|
|
60
55
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
56
|
+
return new Promise((resolve) => {
|
|
57
|
+
try {
|
|
58
|
+
const template = pug.compileFile(output.template ? context.template : filename, Object.assign(options.options, {
|
|
59
|
+
basedir: options.root,
|
|
60
|
+
filters: options.filters
|
|
61
|
+
}))
|
|
66
62
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
63
|
+
output.content = template(context)
|
|
64
|
+
|
|
65
|
+
resolve(output)
|
|
66
|
+
} catch (error) {
|
|
67
|
+
output.error = error
|
|
71
68
|
|
|
72
|
-
|
|
69
|
+
resolve(output)
|
|
70
|
+
}
|
|
71
|
+
})
|
|
73
72
|
}
|
|
74
73
|
|
|
74
|
+
/**
|
|
75
|
+
* @param {import('@vituum/vite-plugin-pug/types').PluginUserConfig} options
|
|
76
|
+
* @returns [import('vite').Plugin]
|
|
77
|
+
*/
|
|
75
78
|
const plugin = (options = {}) => {
|
|
76
|
-
|
|
79
|
+
let resolvedConfig
|
|
80
|
+
let userEnv
|
|
77
81
|
|
|
78
|
-
|
|
82
|
+
options = merge(defaultOptions, options)
|
|
83
|
+
|
|
84
|
+
return [{
|
|
79
85
|
name,
|
|
80
|
-
config
|
|
86
|
+
config (userConfig, env) {
|
|
87
|
+
userEnv = env
|
|
88
|
+
},
|
|
89
|
+
configResolved (config) {
|
|
90
|
+
resolvedConfig = config
|
|
91
|
+
|
|
81
92
|
if (!options.root) {
|
|
82
|
-
options.root = root
|
|
93
|
+
options.root = config.root
|
|
83
94
|
}
|
|
84
95
|
},
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
filename = filename.replace('?raw', '')
|
|
96
|
+
buildStart: async () => {
|
|
97
|
+
if (userEnv.command !== 'build') {
|
|
98
|
+
return
|
|
99
|
+
}
|
|
90
100
|
|
|
101
|
+
await renameBuildStart(resolvedConfig.build.rollupOptions.input, options.formats)
|
|
102
|
+
},
|
|
103
|
+
buildEnd: async () => {
|
|
104
|
+
if (userEnv.command !== 'build') {
|
|
105
|
+
return
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
await renameBuildEnd(resolvedConfig.build.rollupOptions.input, options.formats)
|
|
109
|
+
},
|
|
110
|
+
transformIndexHtml: {
|
|
111
|
+
order: 'pre',
|
|
112
|
+
async transform (content, { path, filename, server }) {
|
|
91
113
|
if (
|
|
92
|
-
!options.
|
|
93
|
-
|
|
94
|
-
!content.startsWith('<script type="application/json" data-format="pug"')
|
|
114
|
+
!options.formats.find(format => filename.replace('.html', '').endsWith(format)) ||
|
|
115
|
+
(filename.replace('.html', '').endsWith('.json') && !content.startsWith('{'))
|
|
95
116
|
) {
|
|
96
117
|
return content
|
|
97
118
|
}
|
|
98
119
|
|
|
99
|
-
if (
|
|
100
|
-
|
|
120
|
+
if (
|
|
121
|
+
(filename.replace('.html', '').endsWith('.json') && content.startsWith('{')) &&
|
|
122
|
+
(JSON.parse(content)?.format && !options.formats.includes(JSON.parse(content)?.format))
|
|
123
|
+
) {
|
|
124
|
+
return content
|
|
125
|
+
}
|
|
101
126
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
127
|
+
if (options.ignoredPaths.find(ignoredPath => minimatch(path.replace('.html', ''), ignoredPath) === true)) {
|
|
128
|
+
return content
|
|
105
129
|
}
|
|
106
130
|
|
|
107
|
-
const render = await renderTemplate(filename, content, options)
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
setTimeout(() => server.ws.send({
|
|
116
|
-
type: 'error',
|
|
117
|
-
err: {
|
|
118
|
-
message: render.error.message,
|
|
119
|
-
plugin: name
|
|
120
|
-
}
|
|
121
|
-
}), 50)
|
|
131
|
+
const render = await renderTemplate({ filename, server, root: resolvedConfig.root }, content, options)
|
|
132
|
+
const renderError = pluginError(render.error, server, name)
|
|
133
|
+
|
|
134
|
+
if (renderError && server) {
|
|
135
|
+
return
|
|
136
|
+
} else if (renderError) {
|
|
137
|
+
return renderError
|
|
122
138
|
}
|
|
123
139
|
|
|
124
140
|
return render.content
|
|
125
141
|
}
|
|
126
142
|
},
|
|
127
|
-
handleHotUpdate({ file, server }) {
|
|
128
|
-
|
|
129
|
-
(typeof options.reload === 'function' && options.reload(file)) ||
|
|
130
|
-
(options.reload && (options.filetypes.html.test(file) || options.filetypes.json.test(file)))
|
|
131
|
-
) {
|
|
132
|
-
server.ws.send({ type: 'full-reload' })
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
143
|
+
handleHotUpdate: ({ file, server }) => pluginReload({ file, server }, options)
|
|
144
|
+
}, pluginBundle(options.formats)]
|
|
136
145
|
}
|
|
137
146
|
|
|
138
147
|
export default plugin
|
package/package.json
CHANGED
|
@@ -1,24 +1,37 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vituum/vite-plugin-pug",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "1.0.0-alpha.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"tsc": "tsc",
|
|
8
|
+
"eslint": "eslint '**/*.js' --fix"
|
|
9
|
+
},
|
|
6
10
|
"dependencies": {
|
|
7
11
|
"pug": "^3.0.2",
|
|
8
12
|
"lodash": "^4.17.21",
|
|
9
|
-
"
|
|
10
|
-
"
|
|
13
|
+
"fast-glob": "^3.2.12",
|
|
14
|
+
"vituum": "^1.0.0-alpha.23",
|
|
15
|
+
"minimatch": "^9.0.1"
|
|
11
16
|
},
|
|
12
17
|
"devDependencies": {
|
|
13
|
-
"
|
|
14
|
-
"eslint
|
|
18
|
+
"@types/node": "^20.3.1",
|
|
19
|
+
"eslint": "^8.43.0",
|
|
20
|
+
"eslint-config-standard": "^17.1.0",
|
|
21
|
+
"typescript": "^5.1.3",
|
|
22
|
+
"vite": "^4.3.9"
|
|
15
23
|
},
|
|
16
24
|
"files": [
|
|
17
|
-
"index.js"
|
|
25
|
+
"index.js",
|
|
26
|
+
"types"
|
|
18
27
|
],
|
|
28
|
+
"exports": {
|
|
29
|
+
".": "./index.js",
|
|
30
|
+
"./types": "./types/*"
|
|
31
|
+
},
|
|
19
32
|
"engines": {
|
|
20
|
-
"node": ">=
|
|
21
|
-
"npm": ">=
|
|
33
|
+
"node": ">=18.0.0",
|
|
34
|
+
"npm": ">=9.0.0"
|
|
22
35
|
},
|
|
23
36
|
"repository": {
|
|
24
37
|
"type": "git",
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
interface PugOptions {
|
|
2
|
+
/** The name of the file being compiled. Used in exceptions, and required for relative includes and extends. Defaults to 'Pug'. */
|
|
3
|
+
filename?: string | undefined,
|
|
4
|
+
/** The root directory of all absolute inclusion. */
|
|
5
|
+
basedir?: string | undefined,
|
|
6
|
+
/** If the doctype is not specified as part of the template, you can specify it here. It is sometimes useful to get self-closing tags and remove mirroring of boolean attributes; see doctype documentation for more information. */
|
|
7
|
+
doctype?: string | undefined,
|
|
8
|
+
/** Adds whitespace to the resulting HTML to make it easier for a human to read using ' ' as indentation. If a string is specified, that will be used as indentation instead (e.g. '\t'). Defaults to false. */
|
|
9
|
+
pretty?: boolean | string | undefined,
|
|
10
|
+
/** Hash table of custom filters. Defaults to undefined. */
|
|
11
|
+
filters?: any,
|
|
12
|
+
/** Use a self namespace to hold the locals. It will speed up the compilation, but instead of writing variable you will have to write self.variable to access a property of the locals object. Defaults to false. */
|
|
13
|
+
self?: boolean | undefined,
|
|
14
|
+
/** If set to true, the tokens and function body are logged to stdout. */
|
|
15
|
+
debug?: boolean | undefined,
|
|
16
|
+
/** If set to true, the function source will be included in the compiled template for better error messages (sometimes useful in development). It is enabled by default unless used with Express in production mode. */
|
|
17
|
+
compileDebug?: boolean | undefined,
|
|
18
|
+
/** Add a list of global names to make accessible in templates. */
|
|
19
|
+
globals?: Array<string> | undefined,
|
|
20
|
+
/** If set to true, compiled functions are cached. filename must be set as the cache key. Only applies to render functions. Defaults to false. */
|
|
21
|
+
cache?: boolean | undefined,
|
|
22
|
+
/** Inline runtime functions instead of require-ing them from a shared version. For compileClient functions, the default is true so that one does not have to include the runtime. For all other compilation or rendering types, the default is false. */
|
|
23
|
+
inlineRuntimeFunctions?: boolean | undefined,
|
|
24
|
+
/** The name of the template function. Only applies to compileClient functions. Defaults to 'template'. */
|
|
25
|
+
name?: string | undefined
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface PluginUserConfig {
|
|
29
|
+
reload?: boolean | Function
|
|
30
|
+
root?: string
|
|
31
|
+
filters?: Object
|
|
32
|
+
globals?: Object
|
|
33
|
+
data?: string | string[]
|
|
34
|
+
formats?: string[]
|
|
35
|
+
options?: PugOptions
|
|
36
|
+
ignoredPaths?: string[]
|
|
37
|
+
}
|