-
Notifications
You must be signed in to change notification settings - Fork 16
Serialize compiled function as module #18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
497185b
update index.html
cho45 f9bac56
serialized feature example
cho45 cb64993
avoid hack
cho45 2846d38
lib/serializer.js
cho45 4b0151a
"/" を name として許可する
cho45 9085948
add usage
cho45 c524138
add tests
cho45 7809ca2
update readme
cho45 6fa06a1
format
cho45 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| #!/usr/bin/env node | ||
|
|
||
| import { serializeTemplates } from '../lib/serializer.js'; | ||
| import { promises as fs } from 'fs'; | ||
| import path from 'path'; | ||
|
|
||
| const USAGE = ` | ||
| Usage: micro-template-serialize <input1.tmpl> ... --output <output.js> [--root <dir>] | ||
|
|
||
| Purpose: | ||
| Reads one or more template files, extracts their content and meta information | ||
| (such as keys defined in <!--meta.keys=[...]-->), and serializes them into a JavaScript file. | ||
| The template ID is determined by the relative path from the root directory (without extension). | ||
|
|
||
| This tool is especially useful for environments where dynamic function generation | ||
| (such as with new Function()) is not allowed, as it outputs pre-serialized ESM modules. | ||
|
|
||
| Arguments: | ||
| <input1.tmpl> ... List of template files to serialize. | ||
| --output <output.js> Output JavaScript file (required). | ||
| --root <dir> Root directory for template IDs (default: current directory). | ||
| --help, -h Show this help message. | ||
|
|
||
| Example: | ||
| micro-template-serialize test/data-test1.tmpl test/data-fizzbuzz.tmpl --output templates.js --root test | ||
|
|
||
| And this will generate a file named 'templates.js' in the current directory. | ||
| You can then import the generated module in your JavaScript code: | ||
|
|
||
| import { extended as template } from './templates.js'; | ||
| const result = template('main', { foo: 'world', baz: 'baz!' }); | ||
| console.log('render result:', result); | ||
|
|
||
| Notes: | ||
| - If a template does not contain a <!--meta.keys=[...]--> comment, a warning will be shown. | ||
| - The output file will contain the serialized templates using the serializeTemplates function. | ||
| - The output file is an ESM module (use 'import' to load it). | ||
| `; | ||
|
|
||
| // --- 引数パース --- | ||
| const args = process.argv.slice(2); | ||
| if (args.includes('--help') || args.includes('-h')) { | ||
| console.log(USAGE); | ||
| process.exit(0); | ||
| } | ||
| let outputFile; | ||
| let rootDir = process.cwd(); | ||
| const inputFiles = []; | ||
| for (let i = 0; i < args.length; i++) { | ||
| if (args[i] === '--output') { | ||
| outputFile = args[++i]; | ||
| } else | ||
| if (args[i] === '--root') { | ||
| rootDir = args[++i]; | ||
| } else { | ||
| inputFiles.push(args[i]); | ||
| } | ||
| } | ||
| if (!outputFile || inputFiles.length === 0) { | ||
| console.error('Usage: micro-template-serialize <input1.tmpl> ... --output templates.js [--root <dir>]'); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| // --- テンプレートファイル読み込み --- | ||
| const templates = {}; | ||
| for (const file of inputFiles) { | ||
| // id を rootDir からの相対パス(拡張子除く)にする | ||
| const relPath = path.relative(rootDir, file); | ||
| const id = relPath.replace(path.extname(relPath), ''); | ||
| const source = await fs.readFile(file, 'utf-8'); | ||
| templates[id] = { source }; | ||
| source.replace(/<!--meta\.(\w+)=(.+?)-->/g, (match, key, value) => { | ||
| templates[id][key] = JSON.parse(value); | ||
| return ''; // Remove the comment | ||
| }); | ||
| if (!templates[id].keys) { | ||
| console.warn(`Warning: Template "${id}" does not have keys defined. Please add <!--meta.keys=["key1", "key2"]--> in the template file.`); | ||
| templates[id].keys = []; | ||
| } | ||
| } | ||
|
|
||
| const code = serializeTemplates(templates); | ||
| await fs.writeFile(outputFile, code); | ||
| console.log(`Wrote: ${outputFile}`); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| #!/usr/bin/env node | ||
|
|
||
| import { template, extended } from './micro-template.js'; | ||
|
|
||
| export function serializeTemplates(target) { | ||
| template.get = id => target[id].source; | ||
| template.cache.clear(); | ||
|
|
||
| let serialized = 'const compiled = {};\n'; | ||
|
|
||
| for (const [id, entry] of Object.entries(target)) { | ||
| const keys = entry.keys || []; | ||
| console.log(`Compiling template: ${id}`); | ||
| const func = extended(id, keys); | ||
| const compiled = func.compiled; | ||
| serialized += `compiled['${id}'] = ` + compiled.toString().replace(/\/\/#.*/g, '') + ';\n'; | ||
| serialized += `compiled['${id}'].keys = ` + JSON.stringify(func.keys) + ';\n'; | ||
| } | ||
|
|
||
| serialized += `const regexp = /[<>"'&]/;\n`; | ||
| serialized += `const escapeHTML = ` + template.escapeHTML.toString() + ';\n'; | ||
|
|
||
| serialized += `const template = ` + (function (id, stash) { | ||
| const me = template; | ||
| const func = compiled[id]; | ||
| if (!func) { | ||
| throw new Error(`Template "${id}" not found.`); | ||
| } | ||
| return func.call(null, me.context = { escapeHTML, line: 1, ret: '', stash }, ...func.keys.map(key => stash[key])); | ||
| }).toString() + ';\n'; | ||
|
|
||
| serialized += `const extended = ` + extended.toString() + ';\n'; | ||
|
|
||
| serialized += `export { template, extended };\n`; | ||
|
|
||
| return serialized; | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| #!/usr/bin/env node | ||
| import { extended as template } from '../_serialized.js'; | ||
|
|
||
| const result = template('main', { foo: 'world', baz: 'baz!' }); | ||
| console.log('render result:', result); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| <!--meta.keys=["year"] --> | ||
|
|
||
| <footer> | ||
| <p>Footer content <%= year %></p> | ||
| </footer> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| <!--meta.keys=["foo", "baz"] --> | ||
|
|
||
| HEADER | ||
| <% wrapper('wrapper', function () { %> | ||
| hello <%= foo %>, | ||
| <% [1,2].forEach( () => { %> | ||
| and <%= baz %> | ||
| <% }) %> | ||
| <% }) %> | ||
| <% include('footer', { year: 2025 }) %> | ||
| FOOTER |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| <!--meta.keys=["content"] --> | ||
|
|
||
| BEFORE CONTENT | ||
| <%=raw content %> | ||
| AFTER CONTENT |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider removing or gating the console.log statement to avoid unwanted logging in production builds.