├── .gitignore ├── __tests__ ├── test-data │ ├── entry.js │ └── example.ejs ├── loader.test.js └── lib │ └── compiler.js ├── babel.config.js ├── .github └── workflows │ └── ci.yml ├── LICENSE ├── package.json ├── index.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | -------------------------------------------------------------------------------- /__tests__/test-data/entry.js: -------------------------------------------------------------------------------- 1 | const dom = require("./example.ejs"); 2 | 3 | dom({ name: "World" }); -------------------------------------------------------------------------------- /__tests__/test-data/example.ejs: -------------------------------------------------------------------------------- 1 | <% let es2015test = -3 * 5; %> 2 |
3 | Hello <%= name %> <%= es2015test %> 4 |
-------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | [ 4 | '@babel/preset-env', 5 | { 6 | targets: { 7 | node: 'current', 8 | }, 9 | }, 10 | ], 11 | ], 12 | }; -------------------------------------------------------------------------------- /__tests__/loader.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @jest-environment node 3 | */ 4 | import compiler from './lib/compiler.js'; 5 | import path from "path"; 6 | 7 | test('Must be able to build js to load ejs', async () => { 8 | const stats = await compiler(path.resolve(__dirname, './test-data/entry.js')); 9 | const output = stats.toJson({source: true}).modules[0].source; 10 | 11 | expect(output).toEqual(expect.anything()); 12 | }); -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Node.js CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-20.04 8 | timeout-minutes: 15 9 | 10 | steps: 11 | - uses: actions/checkout@v2 12 | 13 | - uses: actions/cache@v1 14 | with: 15 | path: node_modules 16 | key: node_modules-${{ hashFiles('**/yarn.lock') }} 17 | restore-keys: | 18 | node_modules- 19 | 20 | - name: npm install 21 | run: npm install 22 | 23 | - name: run unittest 24 | run: | 25 | npm test 26 | -------------------------------------------------------------------------------- /__tests__/lib/compiler.js: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import webpack from 'webpack'; 3 | import { createFsFromVolume, Volume } from 'memfs'; 4 | 5 | /** 6 | * @param {string} fixture fullpath 7 | */ 8 | export default (fixture, options = {}) => { 9 | const compiler = webpack({ 10 | context: __dirname, 11 | entry: fixture, 12 | output: { 13 | path: path.resolve(__dirname), 14 | filename: 'bundle.js', 15 | }, 16 | module: { 17 | rules: [{ 18 | test: /\.ejs$/, 19 | use: { 20 | loader: path.resolve(__dirname, '../../index.js'), 21 | options, 22 | } 23 | }] 24 | } 25 | }); 26 | 27 | compiler.outputFileSystem = createFsFromVolume(new Volume()); 28 | compiler.outputFileSystem.join = path.join.bind(path); 29 | 30 | return new Promise((resolve, reject) => { 31 | compiler.run((err, stats) => { 32 | if (err) reject(err); 33 | if (stats.hasErrors()) reject(stats.toJson().errors); 34 | 35 | resolve(stats); 36 | }); 37 | }); 38 | }; 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Def 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "compile-ejs-loader", 3 | "version": "0.0.3", 4 | "description": "webpack loader use to compile ejs templates (without frontend dependencies)", 5 | "author": "Long Wei", 6 | "license": "MIT", 7 | "repository": "defims/compile-ejs-loader", 8 | "homepage": "https://github.com/defims/compile-ejs-loader", 9 | "bugs": "https://github.com/defims/compile-ejs-loader/issues", 10 | "main": "index.js", 11 | "scripts": { 12 | "test": "jest" 13 | }, 14 | "jest": { 15 | "testEnvironment": "node", 16 | "testPathIgnorePatterns": [ 17 | "__tests__/lib/", 18 | "__tests__/test-data/" 19 | ] 20 | }, 21 | "devDependencies": { 22 | "jest": "^26.6.3", 23 | "@babel/core": "^7.12.10", 24 | "@babel/preset-env": "^7.12.11", 25 | "babel-jest": "^26.6.3", 26 | "memfs": "^3.2.0", 27 | "webpack": "^5.18.0" 28 | }, 29 | "peerDependencies": { 30 | "webpack": "^5.18.0" 31 | }, 32 | "dependencies": { 33 | "ejs": "^3.1.5", 34 | "html-minifier": "^4.0.0", 35 | "uglify-js": "^3.12.5", 36 | "@webpack-contrib/schema-utils": "^1.0.0-beta.0", 37 | "loader-utils": "^2.0.0" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License http://www.opensource.org/licenses/mit-license.php 3 | Author Long Wei 4 | */ 5 | const loaderUtils = require('loader-utils'); 6 | const ejs = require('ejs'); 7 | const UglifyJS = require('uglify-js'); 8 | const htmlmin = require('html-minifier'); 9 | const path = require('path'); 10 | const packageJson = require('./package.json'); 11 | const loaderName = packageJson.name || "compile-ejs-loader"; 12 | 13 | function throwError(message) { 14 | const error = new Error() 15 | error.name = loaderName; 16 | error.message = error.name + '\n\n' + message + '\n'; 17 | error.stack = false; 18 | console.error(error); 19 | } 20 | 21 | module.exports = function(source) { 22 | const options = loaderUtils.getOptions(this) || {}; 23 | 24 | if (!this.webpack) { 25 | throwError('This loader is only usable with webpack'); 26 | } 27 | 28 | this.cacheable(true); 29 | 30 | options.client = true; 31 | options.filename = path.relative(process.cwd(), this.resourcePath); 32 | 33 | if(options.htmlmin) { 34 | source = htmlmin.minify(source, options['htmlminOptions'] || {}); 35 | } 36 | 37 | var template = ejs.compile(source, options); 38 | var minimize = this._compiler.options.optimization.minimize; 39 | 40 | if (!minimize && options.beautify !== false) { 41 | var ast = UglifyJS.parse(template.toString()); 42 | ast.figure_out_scope(); 43 | template = ast.print_to_string({beautify: true}); 44 | } 45 | 46 | return 'module.exports = ' + template; 47 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # compile-ejs-loader for webpack 2 | 3 | [webpack](https://webpack.js.org/) loader use to compile [ejs](https://github.com/mde/ejs) templates. 4 | 5 | ## Installation 6 | 7 | `npm install compile-ejs-loader` 8 | 9 | ## Usage 10 | 11 | [Documentation: Using loaders](https://webpack.js.org/concepts/loaders/#using-loaders) 12 | 13 | ``` javascript 14 | var template = require("compile-ejs-loader!./file.ejs"); 15 | // => returns the template function compiled with ejs templating engine. 16 | 17 | // And then use it somewhere in your code 18 | template(data) // Pass object with data 19 | 20 | // Child Templates 21 | // path is relative to where webpack is being run 22 | <%- include templates/child -%> 23 | ``` 24 | 25 | ## Options 26 | 27 | besides [ejs compile options](https://github.com/mde/ejs#options), you can add these addtion options: 28 | 29 | `beautify` — enable or disable uglify-js beautify of template ast 30 | 31 | `compileDebug` — see ejs compileDebug option 32 | 33 | `htmlmin` — see [htmlminify section](#htmlminify) 34 | 35 | `htmlminOptions` - See [all htmlminify options reference](https://github.com/kangax/html-minifier#options-quick-reference) 36 | 37 | ## webpack config example 38 | 39 | ```javascript 40 | module: { 41 | rules: [{ 42 | test: /\.ejs$/, 43 | loader: 'compile-ejs-loader', 44 | options: { 45 | 'htmlmin': true, 46 | 'htmlminOptions': { 47 | removeComments: true 48 | } 49 | } 50 | }] 51 | } 52 | ``` 53 | 54 | ## License 55 | 56 | MIT (http://www.opensource.org/licenses/mit-license.php) 57 | --------------------------------------------------------------------------------