diff --git a/.eslintrc b/.eslintrc
index 03f2432..eafdd75 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -3,12 +3,10 @@
"rules": {
"indent": ["error", 4],
"no-new": "off",
- "space-before-function-paren": ["error", "never"],
- "import/extensions": ["error", "ignorePackages"],
- "multiline-ternary": ["error", "never"]
+ "import/extensions": ["error", "ignorePackages"]
},
"env": {
"browser": true
},
- "ignorePatterns": ["src", "public"]
+ "ignorePatterns": ["**/*.d.ts"]
}
diff --git a/README.md b/README.md
index 74e9c07..f648ee9 100644
--- a/README.md
+++ b/README.md
@@ -7,52 +7,29 @@
import twig from '@vituum/vite-plugin-twig'
export default {
- plugins: [
- twig({
- reload: true,
- root: null,
- filters: {},
- functions: {},
- extensions: [],
- namespaces: {},
- globals: {
- template: 'path/to/template.twig'
- },
- data: '*.json',
- filetypes: {
- html: /.(json.html|twig.json.html|twig.html)$/,
- json: /.(json.twig.html)$/
- },
- twig: {
- compileOptions: {},
- renderOptions: {}
- }
- })
- ]
+ plugins: [
+ twig()
+ ],
+ build: {
+ rollupOptions: {
+ input: ['index.twig.html']
+ }
+ }
}
```
-Read the [docs](https://vituum.dev/config/integrations-options.html#vituum-twig) to learn more about the plugin options.
+* Read the [docs](https://vituum.dev/plugins/twig.html) to learn more about the plugin options.
+* Use with [Vituum](https://vituum.dev) to get multi-page support.
## Basic usage
```html
-
-
-```
-or
-```html
-
+
{{ title }}
```
or
```html
-
+
{
"template": "path/to/template.twig",
"title": "Hello world"
@@ -62,4 +39,4 @@ or
### Requirements
- [Node.js LTS (16.x)](https://nodejs.org/en/download/)
-- [Vite](https://vitejs.dev/) or [Vituum](https://vituum.dev/)
+- [Vite](https://vitejs.dev/)
diff --git a/index.js b/index.js
index 35a821c..362540f 100644
--- a/index.js
+++ b/index.js
@@ -1,13 +1,22 @@
-import { dirname, resolve, relative } from 'path'
-import fs from 'fs'
-import process from 'node:process'
-import FastGlob from 'fast-glob'
+import { relative, resolve } from 'node:path'
+import fs from 'node:fs'
import lodash from 'lodash'
import Twig from 'twig'
-import chalk from 'chalk'
-import { fileURLToPath } from 'url'
-
-const { name } = JSON.parse(fs.readFileSync(resolve(dirname((fileURLToPath(import.meta.url))), 'package.json')).toString())
+import {
+ getPackageInfo,
+ merge,
+ pluginBundle,
+ pluginMiddleware,
+ pluginReload, pluginTransform,
+ processData
+} from 'vituum/utils/common.js'
+import { renameBuildEnd, renameBuildStart } from 'vituum/utils/build.js'
+
+const { name } = getPackageInfo(import.meta.url)
+
+/**
+ * @type {import('@vituum/vite-plugin-twig/types').PluginUserConfig}
+ */
const defaultOptions = {
reload: true,
root: null,
@@ -15,55 +24,53 @@ const defaultOptions = {
functions: {},
extensions: [],
namespaces: {},
- globals: {},
- data: '',
- filetypes: {
- html: /.(json.html|twig.json.html|twig.html)$/,
- json: /.(json.twig.html)$/
+ globals: {
+ format: 'twig'
},
- twig: {
+ data: ['src/data/**/*.json'],
+ formats: ['twig', 'json.twig', 'json'],
+ ignoredPaths: [],
+ options: {
compileOptions: {},
renderOptions: {}
}
}
-function processData(paths, data = {}) {
- let context = {}
-
- lodash.merge(context, data)
-
- const normalizePaths = Array.isArray(paths) ? paths.map(path => path.replace(/\\/g, '/')) : paths.replace(/\\/g, '/')
-
- FastGlob.sync(normalizePaths).forEach(entry => {
- const path = resolve(process.cwd(), entry)
-
- context = lodash.merge(context, JSON.parse(fs.readFileSync(path).toString()))
- })
-
- return context
-}
-
-const renderTemplate = async(filename, content, options) => {
+const renderTemplate = async ({ filename, server, resolvedConfig }, content, options) => {
+ const initialFilename = filename.replace('.html', '')
const output = {}
- const context = options.data ? processData(options.data, options.globals) : options.globals
-
- const isJson = filename.endsWith('.json.html') || filename.endsWith('.json')
- const isHtml = filename.endsWith('.html') && !options.filetypes.html.test(filename) && !options.filetypes.json.test(filename) && !isJson
-
- if (isJson || isHtml) {
- lodash.merge(context, isHtml ? content : JSON.parse(fs.readFileSync(filename).toString()))
+ const context = options.data
+ ? processData({
+ paths: options.data,
+ root: resolvedConfig.root
+ }, options.globals)
+ : options.globals
+
+ if (initialFilename.endsWith('.json')) {
+ lodash.merge(context, JSON.parse(content))
+
+ if (!options.formats.includes(context.format)) {
+ return new Promise((resolve) => {
+ output.content = content
+ resolve(output)
+ })
+ }
content = '{% include template %}'
if (typeof context.template === 'undefined') {
- console.error(chalk.red(name + ' template must be defined - ' + filename))
- }
+ const error = `${name}: template must be defined for file ${initialFilename}`
- context.template = relative(process.cwd(), context.template).startsWith(relative(process.cwd(), options.root)) ? resolve(process.cwd(), context.template) : resolve(options.root, context.template)
+ return new Promise((resolve) => {
+ output.error = error
+ resolve(output)
+ })
+ }
+ context.template = relative(resolvedConfig.root, context.template).startsWith(relative(resolvedConfig.root, options.root)) ? resolve(resolvedConfig.root, context.template) : resolve(options.root, context.template)
context.template = relative(options.root, context.template)
- } else if (fs.existsSync(filename + '.json')) {
- lodash.merge(context, JSON.parse(fs.readFileSync(filename + '.json').toString()))
+ } else if (fs.existsSync(initialFilename + '.json')) {
+ lodash.merge(context, JSON.parse(fs.readFileSync(`${initialFilename}.json`).toString()))
}
Twig.cache(false)
@@ -71,7 +78,8 @@ const renderTemplate = async(filename, content, options) => {
if (!Array.isArray(options.extensions)) {
throw new TypeError('\'extensions\' needs to be an array of functions!')
} else {
- options.extensions.forEach((name) => {
+ options.extensions.forEach(name => {
+ // noinspection JSCheckFunctionSignatures
Twig.extend(name)
})
}
@@ -92,80 +100,71 @@ const renderTemplate = async(filename, content, options) => {
Twig.extendFilter(name, options.filters[name])
})
- output.content = await Twig.twig(Object.assign({
- allowAsync: true,
- data: content,
- path: options.root + '/',
- namespaces: options.namespaces,
- rethrow: true
- }, options.twig.compileOptions)).renderAsync(context, options.twig.renderOptions).catch((error) => {
- output.error = error
- })
+ return new Promise((resolve) => {
+ const onError = (error) => {
+ output.error = error
+ resolve(output)
+ }
- return output
+ const onSuccess = (content) => {
+ output.content = content
+ resolve(output)
+ }
+
+ Twig.twig(Object.assign({
+ allowAsync: true,
+ data: content,
+ path: options.root + '/',
+ namespaces: options.namespaces,
+ rethrow: true
+ }, options.options.compileOptions)).renderAsync(context, options.options.renderOptions).catch(onError).then(onSuccess)
+ })
}
+/**
+ * @param {import('@vituum/vite-plugin-twig/types').PluginUserConfig} options
+ * @returns [import('vite').Plugin]
+ */
const plugin = (options = {}) => {
- options = lodash.merge(defaultOptions, options)
+ let resolvedConfig
+ let userEnv
+
+ options = merge(defaultOptions, options)
- return {
+ return [{
name,
- config: ({ root }) => {
+ config (userConfig, env) {
+ userEnv = env
+ },
+ configResolved (config) {
+ resolvedConfig = config
+
if (!options.root) {
- options.root = root
+ options.root = config.root
}
},
- transformIndexHtml: {
- enforce: 'pre',
- async transform(content, { path, filename, server }) {
- path = path.replace('?raw', '')
- filename = filename.replace('?raw', '')
-
- if (
- !options.filetypes.html.test(path) &&
- !options.filetypes.json.test(path) &&
- !content.startsWith('