diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e756284..b4d4f2b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,24 @@ # Change log +## 4.1.0 (2024-09-29) + +- feat: add supports the `require` of CommonJS and JSON files in EJS templates: + ```html + <% const data = require('./data.js') %> +
Film: <%= data.title %>
+
Genre: <%= data.genre %>
+ ``` + or + ```html + <% const data = require('./data.json') %> +
Film: <%= data.title %>
+
Genre: <%= data.genre %>
+ ``` +- chore: update peerDependencies +- test: refactor test cases for preprocessor + -## 4.0.0 Release (24-09-08) +## 4.0.0 Release (2024-09-08) ### BREAKING CHANGES diff --git a/package-lock.json b/package-lock.json index 44ef956d..9e60c82f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "html-bundler-webpack-plugin", - "version": "4.0.0", + "version": "4.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "html-bundler-webpack-plugin", - "version": "4.0.0", + "version": "4.1.0", "license": "ISC", "dependencies": { "@types/html-minifier-terser": "^7.0.2", @@ -38,7 +38,7 @@ "handlebars": "^4.7.8", "handlebars-layouts": "^3.1.4", "jest": "^29.7.0", - "liquidjs": "^10.16.7", + "liquidjs": "^10.17.0", "markdown-it": "^14.1.0", "mustache": "^4.2.0", "normalize.css": "^8.0.1", @@ -74,16 +74,16 @@ "url": "https://patreon.com/biodiscus" }, "peerDependencies": { - "ejs": ">=3.1.9", - "favicons": ">=7.1.4", - "handlebars": ">=4.7.7", - "liquidjs": ">=10.7.0", + "ejs": ">=3.1.10", + "favicons": ">=7.2.0", + "handlebars": ">=4.7.8", + "liquidjs": ">=10.17.0", "markdown-it": ">=12", "mustache": ">=4.2.0", "nunjucks": ">=3.2.3", "parse5": ">=7.1.2", "prismjs": ">=1.29.0", - "pug": ">=3.0.2", + "pug": ">=3.0.3", "twig": ">=1.17.1", "webpack": ">=5.81.0" }, @@ -9294,9 +9294,9 @@ } }, "node_modules/liquidjs": { - "version": "10.16.7", - "resolved": "https://registry.npmjs.org/liquidjs/-/liquidjs-10.16.7.tgz", - "integrity": "sha512-vjlBDyPxFgUc6vJB+TbAMcxKKKcm4Ee0rj9Je9lcG1I0lr9xvtHgB/ZdNMNAgsPUvJLkLfdrKRd+KzQ5opPfNg==", + "version": "10.17.0", + "resolved": "https://registry.npmjs.org/liquidjs/-/liquidjs-10.17.0.tgz", + "integrity": "sha512-M4MC5/nencttIJHirl5jFTkl7Yu+grIDLn3Qgl7BPAD3BsbTCQknDxlG5VXWRwslWIjk8lSZZjVq9LioILDk1Q==", "dev": true, "dependencies": { "commander": "^10.0.0" diff --git a/package.json b/package.json index 4252a4a0..8496296e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "html-bundler-webpack-plugin", - "version": "4.0.0", + "version": "4.1.0", "description": "HTML Bundler Plugin for Webpack renders HTML templates containing source files of scripts, styles, images. Supports template engines: Eta, EJS, Handlebars, Nunjucks, Pug, TwigJS. Alternative to html-webpack-plugin.", "keywords": [ "html", @@ -92,16 +92,16 @@ "node": ">=16.20.0" }, "peerDependencies": { - "ejs": ">=3.1.9", - "favicons": ">=7.1.4", - "handlebars": ">=4.7.7", - "liquidjs": ">=10.7.0", + "ejs": ">=3.1.10", + "favicons": ">=7.2.0", + "handlebars": ">=4.7.8", + "liquidjs": ">=10.17.0", "markdown-it": ">=12", "mustache": ">=4.2.0", "nunjucks": ">=3.2.3", "parse5": ">=7.1.2", "prismjs": ">=1.29.0", - "pug": ">=3.0.2", + "pug": ">=3.0.3", "twig": ">=1.17.1", "webpack": ">=5.81.0" }, @@ -170,7 +170,7 @@ "handlebars": "^4.7.8", "handlebars-layouts": "^3.1.4", "jest": "^29.7.0", - "liquidjs": "^10.16.7", + "liquidjs": "^10.17.0", "markdown-it": "^14.1.0", "mustache": "^4.2.0", "normalize.css": "^8.0.1", diff --git a/src/Loader/Preprocessors/Ejs/index.js b/src/Loader/Preprocessors/Ejs/index.js index 16bc6d64..c57a0782 100644 --- a/src/Loader/Preprocessors/Ejs/index.js +++ b/src/Loader/Preprocessors/Ejs/index.js @@ -1,3 +1,5 @@ +const { readFileSync } = require('fs'); +const path = require('path'); const { loadModule } = require('../../../Common/FileUtils'); const { stringifyJSON } = require('../../Utils'); @@ -9,6 +11,19 @@ const includeRegexp = /include\((.+?)(?:\)|,\s*{(.+?)}\))/g; // node module name const moduleName = 'ejs'; +/** + * Require CommonJS or JSON file in EJS template. + * + * @param {string} file + * @param {string} dir + * @return {*} + */ +const requireFile = (file, dir) => { + const fullFilePath = path.join(dir, file); + + return file.endsWith('.json') ? JSON.parse(readFileSync(fullFilePath, 'utf-8')) : require(fullFilePath); +}; + /** * Transform the raw template source to a template function or HTML. * @@ -36,6 +51,10 @@ const preprocessor = (loaderContext, options) => { * @return {string} */ render(source, { resourcePath, data = {} }) { + const contextPath = path.dirname(resourcePath); + + data.require = (file) => requireFile(file, contextPath); + return Ejs.render(source, data, { async: false, root: rootContext, // root path for includes with an absolute path (e.g., /file.html) diff --git a/test/cases/_preprocessor/ejs-require-js/expected/assets/img/apple.02a7c382.png b/test/cases/_preprocessor/ejs-require-js/expected/assets/img/apple.02a7c382.png new file mode 100644 index 00000000..c3b5ce07 Binary files /dev/null and b/test/cases/_preprocessor/ejs-require-js/expected/assets/img/apple.02a7c382.png differ diff --git a/test/cases/_preprocessor/ejs-require-js/expected/index.html b/test/cases/_preprocessor/ejs-require-js/expected/index.html new file mode 100644 index 00000000..3c4b38e3 --- /dev/null +++ b/test/cases/_preprocessor/ejs-require-js/expected/index.html @@ -0,0 +1,20 @@ + + + + + Home + + +

Breaking Bad

+ + apple +
footer
+ + + diff --git a/test/cases/_preprocessor/ejs-require-js/src/data.js b/test/cases/_preprocessor/ejs-require-js/src/data.js new file mode 100644 index 00000000..56ef5116 --- /dev/null +++ b/test/cases/_preprocessor/ejs-require-js/src/data.js @@ -0,0 +1,5 @@ +module.exports = { + title: 'Home', + headline: 'Breaking Bad', + people: ['Walter White', 'Jesse Pinkman'], +}; diff --git a/test/cases/_preprocessor/ejs-require-js/src/home.ejs b/test/cases/_preprocessor/ejs-require-js/src/home.ejs new file mode 100644 index 00000000..910fb251 --- /dev/null +++ b/test/cases/_preprocessor/ejs-require-js/src/home.ejs @@ -0,0 +1,17 @@ +<% const data = require('./data.js') %> + + + + <%= data.title %> + + +

<%= data.headline %>

+ + apple + <%- include('partials/footer.html'); %> + + diff --git a/test/cases/_preprocessor/ejs-require-js/src/partials/footer.html b/test/cases/_preprocessor/ejs-require-js/src/partials/footer.html new file mode 100644 index 00000000..27dee2fa --- /dev/null +++ b/test/cases/_preprocessor/ejs-require-js/src/partials/footer.html @@ -0,0 +1 @@ +
footer
diff --git a/test/cases/_preprocessor/ejs-require-js/webpack.config.js b/test/cases/_preprocessor/ejs-require-js/webpack.config.js new file mode 100644 index 00000000..48275b93 --- /dev/null +++ b/test/cases/_preprocessor/ejs-require-js/webpack.config.js @@ -0,0 +1,40 @@ +const path = require('path'); +const HtmlBundlerPlugin = require('@test/html-bundler-webpack-plugin'); + +module.exports = { + mode: 'production', + + output: { + path: path.join(__dirname, 'dist/'), + }, + + resolve: { + alias: { + '@images': path.join(__dirname, '../../../fixtures/images'), + }, + }, + + plugins: [ + new HtmlBundlerPlugin({ + test: /\.(html|ejs)$/, + entry: { + index: { + import: './src/home.ejs', + }, + }, + preprocessor: 'ejs', + }), + ], + + module: { + rules: [ + { + test: /\.(png|svg|jpe?g|webp)$/i, + type: 'asset/resource', + generator: { + filename: 'assets/img/[name].[hash:8][ext]', + }, + }, + ], + }, +}; diff --git a/test/cases/_preprocessor/ejs-require-json/expected/assets/img/apple.02a7c382.png b/test/cases/_preprocessor/ejs-require-json/expected/assets/img/apple.02a7c382.png new file mode 100644 index 00000000..c3b5ce07 Binary files /dev/null and b/test/cases/_preprocessor/ejs-require-json/expected/assets/img/apple.02a7c382.png differ diff --git a/test/cases/_preprocessor/ejs-require-json/expected/index.html b/test/cases/_preprocessor/ejs-require-json/expected/index.html new file mode 100644 index 00000000..3c4b38e3 --- /dev/null +++ b/test/cases/_preprocessor/ejs-require-json/expected/index.html @@ -0,0 +1,20 @@ + + + + + Home + + +

Breaking Bad

+ + apple +
footer
+ + + diff --git a/test/cases/_preprocessor/ejs-require-json/src/data.json b/test/cases/_preprocessor/ejs-require-json/src/data.json new file mode 100644 index 00000000..1d5b08af --- /dev/null +++ b/test/cases/_preprocessor/ejs-require-json/src/data.json @@ -0,0 +1,5 @@ +{ + "title": "Home", + "headline": "Breaking Bad", + "people": ["Walter White", "Jesse Pinkman"] +} diff --git a/test/cases/_preprocessor/ejs-require-json/src/home.ejs b/test/cases/_preprocessor/ejs-require-json/src/home.ejs new file mode 100644 index 00000000..dfcabea9 --- /dev/null +++ b/test/cases/_preprocessor/ejs-require-json/src/home.ejs @@ -0,0 +1,17 @@ +<% const data = require('./data.json') %> + + + + <%= data.title %> + + +

<%= data.headline %>

+ + apple + <%- include('partials/footer.html'); %> + + diff --git a/test/cases/_preprocessor/ejs-require-json/src/partials/footer.html b/test/cases/_preprocessor/ejs-require-json/src/partials/footer.html new file mode 100644 index 00000000..27dee2fa --- /dev/null +++ b/test/cases/_preprocessor/ejs-require-json/src/partials/footer.html @@ -0,0 +1 @@ +
footer
diff --git a/test/cases/_preprocessor/ejs-require-json/webpack.config.js b/test/cases/_preprocessor/ejs-require-json/webpack.config.js new file mode 100644 index 00000000..48275b93 --- /dev/null +++ b/test/cases/_preprocessor/ejs-require-json/webpack.config.js @@ -0,0 +1,40 @@ +const path = require('path'); +const HtmlBundlerPlugin = require('@test/html-bundler-webpack-plugin'); + +module.exports = { + mode: 'production', + + output: { + path: path.join(__dirname, 'dist/'), + }, + + resolve: { + alias: { + '@images': path.join(__dirname, '../../../fixtures/images'), + }, + }, + + plugins: [ + new HtmlBundlerPlugin({ + test: /\.(html|ejs)$/, + entry: { + index: { + import: './src/home.ejs', + }, + }, + preprocessor: 'ejs', + }), + ], + + module: { + rules: [ + { + test: /\.(png|svg|jpe?g|webp)$/i, + type: 'asset/resource', + generator: { + filename: 'assets/img/[name].[hash:8][ext]', + }, + }, + ], + }, +}; diff --git a/test/integration-pug.test.js b/test/integration-pug.test.js index 56904550..db414930 100644 --- a/test/integration-pug.test.js +++ b/test/integration-pug.test.js @@ -220,7 +220,10 @@ describe('pug-plugin tests', () => { // special cases test('resolve manifest.json via require', () => compareFiles('_pug/resolve-manifest.json-require')); + + // TODO: fix github action issue test('compile template function in js', () => compareFiles('_pug/js-tmpl-entry-js')); + test('inline js and css via query `?inline`', () => compareFiles('_pug/inline-js-css-query')); test('inline CSS in style tag with attributes', () => compareFiles('_pug/inline-css-in-style-tag')); diff --git a/test/preprocessor.test.js b/test/preprocessor.test.js index 1d9c258a..1eca18a7 100644 --- a/test/preprocessor.test.js +++ b/test/preprocessor.test.js @@ -16,6 +16,8 @@ describe('EJS', () => { test('option async', () => compareFiles('_preprocessor/ejs-option-async')); test('option views', () => compareFiles('_preprocessor/ejs-option-views')); test('custom render', () => compareFiles('_preprocessor/ejs-custom-render')); + test('require js', () => compareFiles('_preprocessor/ejs-require-js')); + test('require json', () => compareFiles('_preprocessor/ejs-require-json')); // special cases test('Template with CRLF line separator', () => compareFiles('_preprocessor/ejs-template-clrf'));