├── .eslintignore ├── .eslintrc.json ├── .gitignore ├── .travis.yml ├── README.md ├── index.js ├── lib ├── moduleId.js ├── scriptParser.js ├── templateId.js └── urlParser.js ├── package.json └── test ├── entry.js ├── src └── template.html ├── test.sh ├── unit └── libs.js ├── webpack.config.js └── webpack2.config.js /.eslintignore: -------------------------------------------------------------------------------- 1 | test/out/* -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "google", 3 | "env": { 4 | "node": true, 5 | "mocha": true 6 | }, 7 | "rules": { 8 | "comma-dangle": ["error", "always-multiline"], 9 | "curly": ["error", "all"], 10 | "indent": ["error", 4], 11 | "max-len": ["error", 120], 12 | "no-implicit-coercion": 0, 13 | "no-var": 0 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "4" 4 | - "6" 5 | - "node" 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Angular Template loader for webpack 2 | 3 | Puts HTML partials in the Angular's $templateCache so directives can use templates without initial downloading. 4 | 5 | ## Webpack and loaders 6 | 7 | Webpack is the [webpack](http://webpack.github.io/) and it's module bundler. [Loaders](http://webpack.github.io/docs/using-loaders.html) wrap content in the javascript code that executes in the browser. 8 | 9 | # Install 10 | 11 | `npm install ng-cache-loader` 12 | 13 | # Usage 14 | 15 | You can require html partials via `ng-cache-loader`: 16 | 17 | ``` javascript 18 | require('ng-cache!./demo/template/myPartial.html'); 19 | ``` 20 | 21 | Partial will be available as `ng-include="'myPartial.html'"` 22 | or `templateUrl: 'myPartial.html'`. 23 | 24 | Note that the inline require syntax is used in examples for simplicity. 25 | It's recommended to use webpack [config](#webpack-config). 26 | 27 | ## Named templates 28 | 29 | You can wrap template in the `script` tag: 30 | 31 | ``` html 32 | 33 | 34 | 37 | ``` 38 | 39 | You can have multiple templates in one file: 40 | 41 | ``` html 42 | 43 | 44 | 47 | 48 | 51 | ``` 52 | 53 | You can mix named templates and simple markup: 54 | 55 | ``` html 56 | 57 | 58 | 61 | 62 | 63 |
...
64 | 65 | 68 | ``` 69 | 70 | ## Prefix 71 | 72 | Prefix adds path left of template name: 73 | 74 | ``` javascript 75 | require('ng-cache?prefix=public/templates!./path/to/myPartial.html') 76 | // => ng-include="'public/templates/myPartial.html'" 77 | ``` 78 | 79 | Prefix can mask the real directory with the explicit value 80 | or retrieve the real directory name (use `*` or `[dir]`): 81 | 82 | ``` javascript 83 | require('ng-cache?prefix=public/*/templates!./path/to/myPartial.html') 84 | // => ng-include="'public/path/templates/myPartial.html'" 85 | ``` 86 | 87 | Prefix can strip the real directory name (use `//`): 88 | 89 | ``` javascript 90 | require('ng-cache?prefix=public/*//*/templates!./far/far/away/path/to/myPartial.html') 91 | // => ng-include="'public/far/path/templates/myPartial.html'" 92 | ``` 93 | 94 | Prefix can be extended through a directory tree (use `**` or `[dirs]`). See the next section. 95 | 96 | ## Root 97 | 98 | You can specify root directory for templates separated by a colon `prefix=root:**`. 99 | It is enough to specify a single directory name. Prefix counts real template path from right to left and takes first (rightmost) occurance of the root directory. 100 | 101 | ``` 102 | /User/packman/Projects/packman/ 103 | ├─ app/tmpls/field.html 104 | └─ components/skins/tmpls/yellow.html 105 | ``` 106 | 107 | With this directory tree you require templates from the inside of `app/tmpls` and `components/skins/tmpls`: 108 | 109 | ``` javascript 110 | require('ng-cache?prefix=packman:**!./field.html') 111 | // => ng-include="'app/tmpls/field.html'" 112 | 113 | require('ng-cache?prefix=packman:**!./yellow.html') 114 | // => ng-include="'components/skins/tmpls/yellow.html'" 115 | ``` 116 | 117 | It is also possible to combine wildcards in prefix, i.e. `prefix=packman:**/tmpls//*`. 118 | 119 | ## Name 120 | 121 | Use `name` query parameter to strip file extension or add suffix: 122 | 123 | ``` javascript 124 | // 125 | require('ng-cache?name=[name].tpl!./field.html') 126 | // => ng-include="'field.tpl'" 127 | 128 | require('ng-cache?name=[name]-foo.[ext]!./field.html') 129 | // => ng-include="'field-foo.html'" 130 | ``` 131 | 132 | Note. File extension are defined as any char sequence after the last `.`. 133 | 134 | ## Module 135 | 136 | By default, templates will be added to the default AngularJS 'ng' module run() method. 137 | Use this parameter to use a different module name: 138 | 139 | ``` javascript 140 | require('ng-cache?module=moduleName!./path/to/myPartial.html') 141 | ``` 142 | 143 | If the module does not exist it is created. 144 | 145 | #### Dynamic pattern for Module: 146 | 147 | ``` javascript 148 | require('ng-cache?module=moduleName.[root]&prefix=packs:**!./packs/path/to/myPartial.html') 149 | ``` 150 | 151 | In such query `[root]` means that first part of `templateId` *(here it is `path/to/myPartial.html`)* will be stripped out and placed as a part of `moduleId`. 152 | 153 | In current example resulting values: 154 | - `moduleId`: `"moduleName.path"` 155 | - `templateId`: `"to/myPartial.html"` 156 | 157 | Useful in case you want save few bytes. 158 | 159 | ## Template id 160 | 161 | To obtain template id use `exportIdOnly` query parameter. Loader exports `id` of a template. 162 | 163 | ```javascript 164 | var template = require('ng-cache?exportIdOnly!./field.html') 165 | 166 | $('#wrapper').html(`
`); 167 | angular.bootstrap($('#bootstrapElement'), [someModule]); 168 | ``` 169 | 170 | To obtain both template id and html partial use `exportId` query parameter. Loader exports object with `id` and `template` keys. 171 | 172 | ```javascript 173 | var template = require('ng-cache?exportId!./field.html') 174 | 175 | $('#wrapper').html(`
`); 176 | angular.bootstrap($('#bootstrapElement'), [someModule]); 177 | ``` 178 | 179 | ## Webpack config 180 | 181 | Match `.html` extension with loader: 182 | 183 | ``` javascript 184 | module: { 185 | loaders: [ 186 | { 187 | test: /\.html$/, 188 | loader: "ng-cache?prefix=[dir]/[dir]" 189 | } 190 | ] 191 | } 192 | ``` 193 | 194 | Note that the inline require syntax is used in examples for simplicity. It's recommended to use webpack config. 195 | Please see this [comment](https://github.com/webpack/webpack/issues/1626#issuecomment-156758230) 196 | and the [manual](https://webpack.github.io/docs/using-loaders.html#loaders-in-require). 197 | 198 | ## HTML minification 199 | 200 | Minification is enabled by default. You can switch it off by setting `-minimize`: 201 | ```javascript 202 | ng-cache?-minimize 203 | ``` 204 | 205 | The [html-minifier](https://github.com/kangax/html-minifier) is used for templates minification with the default options: 206 | ```javascript 207 | { 208 | removeComments: true, 209 | removeCommentsFromCDATA: true, 210 | collapseWhitespace: true, 211 | conservativeCollapse: true, 212 | preserveLineBreaks: true, 213 | removeEmptyAttributes: true, 214 | keepClosingSlash: true 215 | } 216 | ``` 217 | 218 | You can override any of options with the negative query parameter: 219 | 220 | ```javascript 221 | ng-cache?-conservativeCollapse&-preserveLineBreaks 222 | ``` 223 | 224 | Or you can extend defaults with `minimizeOptions`: 225 | ```javascript 226 | var minimizeOptions = { 227 | conservativeCollapse: false, 228 | preserveLineBreaks: false 229 | }; 230 | module.exports = { 231 | module: { 232 | loaders: [ 233 | {test: /\.html$/, loader: 'ng-cache?minimizeOptions=' + JSON.stringify(minimizeOptions)} 234 | ] 235 | } 236 | } 237 | ``` 238 | 239 | ## URL resolve 240 | 241 | Relative links to the local images are resolved by default (to prevent it use `-url` query param). 242 | 243 | ``` html 244 | 245 | 246 | 247 | 248 | 249 | ``` 250 | 251 | Use this in conjunction with [url-loader](https://github.com/webpack/url-loader). For instance: 252 | 253 | ``` javascript 254 | require('url?name=img/[name].[ext]!ng-cache!./templates/myPartial.html') 255 | ``` 256 | 257 | Using webpack config is more convenience: 258 | 259 | ``` javascript 260 | module: { 261 | loaders: [ 262 | { test: /\.html$/, loader: "ng-cache?prefix=[dir]/[dir]" }, 263 | { test: /\.png$/, loader: 'url?name=img/[name].[ext]&mimetype=image/png' }, 264 | { test: /\.gif$/, loader: 'url?name=img/[name].[ext]&mimetype=image/gif' } 265 | ] 266 | }, 267 | ``` 268 | 269 | To switch off url resolving use `-url` query param: 270 | 271 | ``` javascript 272 | require('ng-cache?-url!./myPartial.html') 273 | ``` 274 | 275 | # License 276 | 277 | MIT (http://www.opensource.org/licenses/mit-license.php) 278 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License http://www.opensource.org/licenses/mit-license.php 3 | Author Andrey Koperskiy @teux 4 | */ 5 | var extend = require("extend"); 6 | var htmlMinifier = require("html-minifier"); 7 | var loaderUtils = require("loader-utils"); 8 | var scriptParser = require('./lib/scriptParser.js'); 9 | var urlParser = require('./lib/urlParser.js'); 10 | var getTemplateId = require('./lib/templateId.js'); 11 | var getModuleId = require('./lib/moduleId.js'); 12 | 13 | var PRE_STUB = 'var angular=window.angular,ngModule;\n' + 14 | 'try {ngModule=angular.module(["${mod}"])}\n' + 15 | 'catch(e){ngModule=angular.module("${mod}",[])}'; 16 | 17 | var STUB = 'var v${i}=${val};\n' + 18 | 'var id${i}="${key}";\n' + 19 | // added injector to load $templateCache for dynamic chunks 20 | 'var inj=angular.element(window.document).injector();\n' + 21 | 'if(inj){inj.get("$templateCache").put(id${i},v${i});}\n' + 22 | 'else{ngModule.run(["$templateCache",function(c){c.put(id${i},v${i})}]);}'; 23 | 24 | /** 25 | * Replaces placeholders with values. 26 | * @param {string} stub Template ith placeholders. 27 | * @param {Object} values Key-value pairs. 28 | * @return {string} Resolved template. 29 | */ 30 | function supplant(stub, values) { 31 | return stub.replace(/\$\{([^}]+)\}/g, function(match, key) { 32 | return values[key] || match; 33 | }); 34 | } 35 | /** 36 | * Replaces urls with `require(url)` for further processing with url-loader or file-loader. 37 | * @param {Object} query ng-cache-loader options. 38 | * @param {string} src Template text. 39 | * @return {string} JSON 40 | */ 41 | function resolveUrl(query, src) { 42 | return query.url === false ? 43 | JSON.stringify(src) : 44 | urlParser(src); 45 | } 46 | 47 | module.exports = function(source) { 48 | var opts = { 49 | minimize: true, 50 | // next are html-minifier default options 51 | removeComments: true, 52 | removeCommentsFromCDATA: true, 53 | collapseWhitespace: true, 54 | conservativeCollapse: true, 55 | preserveLineBreaks: true, 56 | removeEmptyAttributes: true, 57 | keepClosingSlash: true, 58 | }; 59 | var minimizeOpts; 60 | var moduleId = 'ng'; 61 | var result = []; 62 | var scripts; 63 | var html; 64 | var scr; 65 | 66 | if (this.cacheable) { 67 | this.cacheable(); 68 | } 69 | 70 | // webpack1 or webpack2 with legacy query format 71 | if (typeof this.query === 'string') { 72 | // minimizeOpts is JSON inside query string 73 | minimizeOpts = this.query.match(/&?minimizeOptions[\s\n]*=[\s\n]*([^&]*)/); 74 | 75 | if (minimizeOpts) { 76 | this.query = this.query.replace(minimizeOpts[0], ''); 77 | } 78 | 79 | try { 80 | minimizeOpts = minimizeOpts && JSON.parse(minimizeOpts[1]); 81 | } catch (e) { 82 | throw new Error('Invalid value of query parameter minimizeOptions'); 83 | } 84 | } 85 | 86 | // Parse query and append minimize options 87 | var options = loaderUtils.getOptions ? 88 | loaderUtils.getOptions(this) : 89 | loaderUtils.parseQuery(this.query); 90 | extend(opts, minimizeOpts, options); 91 | 92 | if (opts.minimize) { 93 | try { 94 | source = htmlMinifier.minify(source, extend({}, opts)); 95 | } catch (e) { 96 | this.emitWarning(e.toString() + '\nUsing unminified HTML'); 97 | } 98 | } 99 | 100 | scripts = scriptParser.parse('root', source, {scripts: []}).scripts; 101 | source = Array.prototype.slice.apply(source); 102 | 103 | // Prepare named templates 104 | while (scripts.length) { 105 | scr = scripts.pop(); 106 | html = source 107 | .splice(scr.idx, scr.len) 108 | .splice(scr.contIdx, scr.contLen) 109 | .join(''); 110 | if (scr.id) { 111 | result.push({ 112 | key: scr.id, 113 | val: resolveUrl(opts, html), 114 | i: result.length + 1, 115 | }); 116 | } else { 117 | source.splice(scr.idx, 0, html); 118 | } 119 | } 120 | // Prepare the ramaining templates (means w/o `script` tag or w/o `id` attribute) 121 | source = source.join(''); 122 | 123 | if (/[^\s]/.test(source) || !result.length) { 124 | var templateId = getTemplateId.call(this, source); 125 | var mod = getModuleId.call(this, templateId); 126 | moduleId = mod.moduleId; 127 | result.push({ 128 | key: mod.templateId, 129 | val: resolveUrl(opts, source), 130 | i: result.length + 1, 131 | }); 132 | } 133 | 134 | result = result.map(supplant.bind(null, STUB)); 135 | 136 | // Return template string or id/template pair as module exports 137 | if (opts.exportId) { 138 | result.push('exports.id=id' + result.length + ';\nexports.template=v' + result.length + ';'); 139 | } else if (opts.exportIdOnly) { 140 | result.push('module.exports=id' + result.length + ';'); 141 | } else { 142 | result.push('module.exports=v' + result.length + ';'); 143 | } 144 | result.unshift(supplant(PRE_STUB, {mod: moduleId})); 145 | 146 | return result.join('\n'); 147 | }; 148 | -------------------------------------------------------------------------------- /lib/moduleId.js: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License http://www.opensource.org/licenses/mit-license.php 3 | Author Alexander Merkulov @merqlove 4 | */ 5 | var loaderUtils = require("loader-utils"); 6 | 7 | /** 8 | * Process Module ID. 9 | * @param {string} templateId Template ID. 10 | * @return {object} Module ID, New Template ID. 11 | */ 12 | module.exports = function(templateId) { 13 | var root = '[root]'; 14 | var sep = '/'; 15 | var defaultName = 'ng'; 16 | 17 | var query = loaderUtils.getOptions ? 18 | loaderUtils.getOptions(this) : 19 | loaderUtils.parseQuery(this.query); 20 | var moduleId = query.module || defaultName; 21 | var newTemplateId = templateId; 22 | 23 | if(~moduleId.indexOf(root)) { 24 | var path = templateId.split(sep); 25 | var suffix = path.shift(); 26 | moduleId = moduleId.replace(root, suffix); 27 | newTemplateId = path.join(sep); 28 | } 29 | 30 | return { 31 | moduleId: moduleId, 32 | templateId: newTemplateId 33 | }; 34 | }; 35 | -------------------------------------------------------------------------------- /lib/scriptParser.js: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License http://www.opensource.org/licenses/mit-license.php 3 | Author Andrey Koperskiy @teux 4 | */ 5 | var Parser = require('fastparse'); 6 | 7 | module.exports = new Parser({ 8 | root: { 9 | '': function(match, idx, len) { 14 | if (this.isTemplate) { 15 | this.scripts.push({ 16 | id: this.id, // template name 17 | idx: this.idx, // script begin index 18 | len: idx + len - this.idx, // script including final script tag length 19 | contIdx: this.contIdx, // content begin index 20 | contLen: idx - this.idx - this.contIdx, // content up to final script tag length 21 | }); 22 | } 23 | this.isTemplate = this.idx = this.contIdx = this.id = undefined; 24 | }, 25 | }, 26 | scriptTag: { 27 | 'type[\\s\\n]*=[\\s\\n]*[\'"]': 'typeAttr', 28 | 'id[\\s\\n]*=[\\s\\n]*[\'"]': 'idAttr', 29 | '>': function(match, idx) { 30 | this.contIdx = idx - this.idx + 1; 31 | return 'root'; 32 | }, 33 | }, 34 | typeAttr: { 35 | 'text/ng-template': function() { 36 | this.isTemplate = true; 37 | }, 38 | '[\'"]': 'scriptTag', 39 | }, 40 | idAttr: { 41 | '[^\'"\\s\\n]+': function(match) { 42 | this.id = match; 43 | }, 44 | '[\'"]': 'scriptTag', 45 | }, 46 | }); 47 | -------------------------------------------------------------------------------- /lib/templateId.js: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License http://www.opensource.org/licenses/mit-license.php 3 | Author Andrey Koperskiy @teux 4 | */ 5 | var loaderUtils = require("loader-utils"); 6 | 7 | /** 8 | * Process file name. 9 | * @param {string} pattern Name pattern, i.e. [name]-1.[ext]. 10 | * @param {string} source Template content (for hash calculation - not implemented now). 11 | * @param {string} file File name. With prefix if defined. 12 | * @return {*} File name according with template. 13 | */ 14 | var processName = function(pattern, source, file) { 15 | var params = { 16 | name: '', 17 | ext: '', 18 | hash: '[hash]', 19 | }; 20 | var re = new RegExp('\\[(' + Object.keys(params).join('|') + ')\\]', 'g'); 21 | var splitted; 22 | var isValid; 23 | var match; 24 | var name; 25 | 26 | if (pattern) { 27 | // It may contain no more than one [name], [ext], [hash] in any order 28 | // Note. hash is not supported now 29 | match = pattern.match(re); 30 | 31 | isValid = !match || !match.some(function(p, i) { 32 | return match.indexOf(p) !== i; 33 | }); 34 | } 35 | 36 | if (!isValid) { 37 | return file; 38 | } 39 | 40 | splitted = file.split('/'); 41 | params.name = splitted.pop(); 42 | match = params.name.match(/^(.+)\.+(.+)$/); 43 | 44 | if (match) { 45 | params.name = match[1]; 46 | params.ext = match[2] || ''; 47 | } 48 | 49 | name = pattern.replace(re, function(p, key) { 50 | return params[key]; 51 | }); 52 | 53 | splitted.push(name); 54 | return splitted.join('/'); 55 | }; 56 | 57 | /** 58 | * Process prefix an file name. 59 | * @param {string} source Template content. 60 | * @return {string} Template ID. 61 | */ 62 | module.exports = function(source) { 63 | var sep = '/'; 64 | var rootSep = ':'; 65 | var dirPh = ['*', '[dir]']; 66 | var dirsPh = ['**', '[dirs]']; 67 | 68 | var query = loaderUtils.getOptions ? 69 | loaderUtils.getOptions(this) : 70 | loaderUtils.parseQuery(this.query); 71 | var pref = query.prefix || ''; 72 | var path = this.resource; 73 | var isAbsolute; 74 | var root; 75 | var file; 76 | var dir; 77 | var i; 78 | 79 | // Change separators to unix style 80 | pref = pref.replace(/\\/g, sep); 81 | path = path.replace(/\\/g, sep); 82 | 83 | // No prefix defined - return file name 84 | if (!pref) { 85 | file = path.split(sep).pop(); 86 | return processName(query.name, source, file); 87 | } 88 | 89 | // Strip root from path and pref 90 | if (~pref.indexOf(rootSep)) { 91 | root = pref.split(rootSep); 92 | pref = root.pop(); 93 | root = root.join(rootSep); 94 | path = path.split(root).pop().replace(/^\//, ''); 95 | } 96 | 97 | // Split and reverse path, get file name 98 | path = path.split(sep); 99 | // Remove first empty chunk 100 | if (!path[0]) { 101 | path.shift(); 102 | } 103 | path.reverse(); 104 | file = path.shift(); 105 | 106 | // Split prefix and replace `[dirs]` by `**` for consistency 107 | pref = pref.split(sep).map(function(dir) { 108 | return ~dirsPh.indexOf(dir) ? dirsPh[0] : dir; 109 | }); 110 | 111 | // Remove empty first chunk if prefix starts with slash 112 | if (!pref[0]) { 113 | isAbsolute = true; 114 | pref.shift(); 115 | } 116 | // Remove empty last chunk if prefix ends with slash 117 | if (!pref[pref.length - 1]) { 118 | pref.pop(); 119 | } 120 | 121 | // Replace `**` by a number of `*` in accordance with the path length 122 | pref = pref.reduce(function(res, dir, i) { 123 | var n = 1; 124 | 125 | if (dir === dirsPh[0]) { 126 | // extend only first appearance 127 | if (pref.indexOf(dir) === i) { 128 | n += Math.max(0, path.length - pref.length); 129 | } 130 | dir = dirPh[0]; 131 | } 132 | while (n--) { 133 | res.push(dir); 134 | } 135 | return res; 136 | }, []); 137 | 138 | i = pref.length; 139 | 140 | while (i--) { 141 | dir = pref.pop(); 142 | if (!~dirPh.indexOf(dir)) { 143 | path[0] = dir; 144 | } 145 | dir = path.shift(); 146 | if (dir) { 147 | pref.unshift(dir); 148 | } 149 | } 150 | 151 | // Return first empty chunk to be absolute 152 | if (isAbsolute && pref[0]) { 153 | pref.unshift(''); 154 | } 155 | 156 | pref.push(file); 157 | file = pref.join(sep); 158 | 159 | return processName(query.name, source, file); 160 | }; 161 | -------------------------------------------------------------------------------- /lib/urlParser.js: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License http://www.opensource.org/licenses/mit-license.php 3 | Author Andrey Koperskiy @teux 4 | */ 5 | var Parser = require("fastparse"); 6 | var relativeImageUrl = /^[^/][^:]+(?:\.png|\.bmp|\.raw|\.jpg|\.jpeg|\.tiff|\.gif|\.svg)$/; 7 | 8 | Parser = new Parser({ 9 | root: { 10 | '<[^\\s/>]+': 'tag', 11 | }, 12 | tag: { 13 | '[\\s\\n](md-svg-)?src[\\s\\n]*=[\\s\\n]*[\'"]': 'srcAttr', 14 | '>': 'root', 15 | }, 16 | srcAttr: { 17 | '[^\'"]+': function(match, idx) { 18 | if (relativeImageUrl.test(match)) { 19 | this.urls.push({idx: idx, path: match}); 20 | } 21 | return 'tag'; 22 | }, 23 | '[\'"]': 'tag', 24 | }, 25 | }); 26 | 27 | module.exports = function(src) { 28 | var urls = Parser.parse('root', src, {urls: []}).urls; 29 | var i = urls.length; 30 | var result = []; 31 | 32 | while (i--) { 33 | result.push(JSON.stringify(src.substr(urls[i].idx + urls[i].path.length))); 34 | result.push(' + require("' + urls[i].path + '") + '); 35 | src = src.substr(0, urls[i].idx); 36 | } 37 | result.push(JSON.stringify(src)); 38 | result.reverse(); 39 | return result.join(''); 40 | }; 41 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ng-cache-loader", 3 | "version": "0.0.26", 4 | "description": "Puts HTML partials in the Angular's $templateCache.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "test/test.sh" 8 | }, 9 | "keywords": [ 10 | "angular", 11 | "template", 12 | "cache", 13 | "webpack", 14 | "loader" 15 | ], 16 | "author": { 17 | "name": "Andrey Koperskiy", 18 | "email": "github@teux.ru", 19 | "url": "https://github.com/teux" 20 | }, 21 | "license": "MIT", 22 | "devDependencies": { 23 | "chai": "^3.2.0", 24 | "eslint": "^2.13.1", 25 | "eslint-config-google": "^0.6.0", 26 | "mocha": "^2.3.0", 27 | "webpack": "^2.4.1" 28 | }, 29 | "dependencies": { 30 | "extend": "^3.0.0", 31 | "fastparse": "^1.0.0", 32 | "html-minifier": "^3.0.2", 33 | "loader-utils": "^1.1.0" 34 | }, 35 | "directories": { 36 | "test": "test" 37 | }, 38 | "repository": { 39 | "type": "git", 40 | "url": "https://github.com/teux/ng-cache-loader.git" 41 | }, 42 | "bugs": { 43 | "url": "https://github.com/teux/ng-cache-loader/issues" 44 | }, 45 | "homepage": "https://github.com/teux/ng-cache-loader" 46 | } 47 | -------------------------------------------------------------------------------- /test/entry.js: -------------------------------------------------------------------------------- 1 | require('./src/template.html'); 2 | -------------------------------------------------------------------------------- /test/src/template.html: -------------------------------------------------------------------------------- 1 | 9 | 10 |
11 |

Second View

12 |

About me

13 |
14 | 15 | 20 | 21 |
22 |

Second View

23 |

About you

24 |
25 | 26 | -------------------------------------------------------------------------------- /test/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # unit 4 | ./node_modules/mocha/bin/mocha test/unit 5 | 6 | # build example in test/out/main.out.js 7 | ./node_modules/webpack/bin/webpack.js --config=test/webpack.config.js -------------------------------------------------------------------------------- /test/unit/libs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by teux on 04.09.15. 3 | */ 4 | var expect = require('chai').expect; 5 | var path = require('path'); 6 | var cwd = process.cwd(); 7 | var libPath; 8 | var lib; 9 | 10 | libPath = 'lib/templateId'; 11 | moduleLibPath = 'lib/moduleId'; 12 | lib = require(path.join(cwd, libPath)); 13 | moduleLib = require(path.join(cwd, moduleLibPath)); 14 | 15 | describe(libPath, function() { 16 | var resources = [ 17 | '/Users/myself/Projects/packman/web_modules/angular-ui-bootstrap/template/popover/popover.html', 18 | '/Users/myself/Projects/packman/components/article/actions/actions.html', 19 | 'W:\\Projects\\packman\\web_modules\\angular-ui-bootstrap\\template\\popover\\popover.html', 20 | 'W:\\Projects\\packman\\components\\article\\actions\\actions.html', 21 | ]; 22 | /** 23 | * Calls library. 24 | * @param {string} resource Absolute template path. 25 | * @param {string} [prefix] Prefix. 26 | * @return {string} Result 27 | */ 28 | var run = function(resource, prefix) { 29 | var params = {resource: resource}; 30 | 31 | params.query = prefix !== undefined ? 32 | '?prefix=' + prefix : 33 | '?'; 34 | return lib.call(params); 35 | }; 36 | 37 | var getFile = function(path) { 38 | return path.replace(/\\/g, '/').split('/').pop(); 39 | }; 40 | 41 | var alternation = function(res, pref) { 42 | var odd; 43 | var abs; 44 | 45 | pref = pref.replace(/\\/g, '/').split('/'); 46 | 47 | if (pref[0] === '') { 48 | abs = true; 49 | pref.shift(); 50 | } 51 | odd = !!~['[dir]', '[dirs]', '*', '**'].indexOf(pref[0]); 52 | 53 | res = res.replace(/\\/g, '/').split('/'); 54 | res = res.slice(res.length - 5); 55 | pref[odd ? 0 : 1] = res[odd ? 0 : 1]; 56 | pref[odd ? 2 : 3] = res[odd ? 2 : 3]; 57 | if (abs) { 58 | pref.unshift(''); 59 | } 60 | pref.push(res[4]); 61 | return pref.join('/'); 62 | }; 63 | 64 | describe('without prefix', function() { 65 | it('#should return file name', function() { 66 | resources.forEach(function(res) { 67 | var file = getFile(res); 68 | expect(run(res)).to.equal(file); 69 | expect(run(res), '').to.equal(file); 70 | }); 71 | }); 72 | }); 73 | 74 | describe('explicit prefix', function() { 75 | it('#should be relative', function() { 76 | var pref = 'app/tmpl'; 77 | resources.forEach(function(res) { 78 | expect(run(res, pref)).to.equal(pref + '/' + getFile(res)); 79 | }); 80 | }); 81 | it('#should be absolute', function() { 82 | var pref = '/app/tmpl'; 83 | resources.forEach(function(res) { 84 | expect(run(res, pref)).to.equal(pref + '/' + getFile(res)); 85 | }); 86 | }); 87 | it('#should be absolute without unnecessary slash', function() { 88 | var pref = '/app/tmpl/'; 89 | resources.forEach(function(res) { 90 | expect(run(res, pref)).to.equal(pref + getFile(res)); 91 | }); 92 | }); 93 | }); 94 | 95 | describe('explicit prefix (Win style)', function() { 96 | it('#should be relative', function() { 97 | var pref = 'app\\tmpl'; 98 | resources.forEach(function(res) { 99 | expect(run(res, pref)).to.equal('app/tmpl/' + getFile(res)); 100 | }); 101 | }); 102 | it('#should be absolute', function() { 103 | var pref = '\\app\\tmpl'; 104 | resources.forEach(function(res) { 105 | expect(run(res, pref)).to.equal('/app/tmpl/' + getFile(res)); 106 | }); 107 | }); 108 | it('#should be absolute without unnecessary slash', function() { 109 | var pref = '\\app\\tmpl\\'; 110 | resources.forEach(function(res) { 111 | expect(run(res, pref)).to.equal('/app/tmpl/' + getFile(res)); 112 | }); 113 | }); 114 | }); 115 | 116 | describe('take from path (relative prefix)', function() { 117 | it('#should take odd chunks', function() { 118 | var pref = '*/dir1/*/dir2'; 119 | resources.forEach(function(res) { 120 | expect(run(res, pref)).to.equal(alternation(res, pref)); 121 | }); 122 | pref = '[dir]/dir1/[dir]/dir2'; 123 | resources.forEach(function(res) { 124 | expect(run(res, pref)).to.equal(alternation(res, pref)); 125 | }); 126 | }); 127 | it('#should take even chunks', function() { 128 | var pref = 'dir1/*/dir2/*'; 129 | resources.forEach(function(res) { 130 | expect(run(res, pref)).to.equal(alternation(res, pref)); 131 | }); 132 | pref = 'dir1/[dir]/dir2/[dir]'; 133 | resources.forEach(function(res) { 134 | expect(run(res, pref)).to.equal(alternation(res, pref)); 135 | }); 136 | }); 137 | }); 138 | 139 | describe('take from path (absolute prefix)', function() { 140 | it('#should take odd chunks', function() { 141 | var pref = '/*/dir1/*/dir2'; 142 | resources.forEach(function(res) { 143 | expect(run(res, pref)).to.equal(alternation(res, pref)); 144 | }); 145 | pref = '/[dir]/dir1/[dir]/dir2'; 146 | resources.forEach(function(res) { 147 | expect(run(res, pref)).to.equal(alternation(res, pref)); 148 | }); 149 | }); 150 | it('#should take even chunks', function() { 151 | var pref = '/dir1/*/dir2/*'; 152 | resources.forEach(function(res) { 153 | expect(run(res, pref)).to.equal(alternation(res, pref)); 154 | }); 155 | pref = '/dir1/[dir]/dir2/[dir]'; 156 | resources.forEach(function(res) { 157 | expect(run(res, pref)).to.equal(alternation(res, pref)); 158 | }); 159 | }); 160 | }); 161 | 162 | describe('take from path (relative prefix Win style)', function() { 163 | it('#should take odd chunks', function() { 164 | var pref = '*\\dir1\\*\\dir2'; 165 | resources.forEach(function(res) { 166 | expect(run(res, pref)).to.equal(alternation(res, pref)); 167 | }); 168 | pref = '[dir]\\dir1\\[dir]\\dir2'; 169 | resources.forEach(function(res) { 170 | expect(run(res, pref)).to.equal(alternation(res, pref)); 171 | }); 172 | }); 173 | it('#should take even chunks', function() { 174 | var pref = 'dir1\\*\\dir2\\*'; 175 | resources.forEach(function(res) { 176 | expect(run(res, pref)).to.equal(alternation(res, pref)); 177 | }); 178 | pref = 'dir1\\[dir]\\dir2\\[dir]'; 179 | resources.forEach(function(res) { 180 | expect(run(res, pref)).to.equal(alternation(res, pref)); 181 | }); 182 | }); 183 | }); 184 | 185 | describe('take from path (absolute prefix Win style)', function() { 186 | it('#should take odd chunks', function() { 187 | var pref = '\\*\\dir1\\*\\dir2'; 188 | resources.forEach(function(res) { 189 | expect(run(res, pref)).to.equal(alternation(res, pref)); 190 | }); 191 | pref = '\\[dir]\\dir1\\[dir]\\dir2'; 192 | resources.forEach(function(res) { 193 | expect(run(res, pref)).to.equal(alternation(res, pref)); 194 | }); 195 | }); 196 | it('#should take even chunks', function() { 197 | var pref = '\\dir1\\*\\dir2\\*'; 198 | resources.forEach(function(res) { 199 | expect(run(res, pref)).to.equal(alternation(res, pref)); 200 | }); 201 | pref = '\\dir1\\[dir]\\dir2\\[dir]'; 202 | resources.forEach(function(res) { 203 | expect(run(res, pref)).to.equal(alternation(res, pref)); 204 | }); 205 | }); 206 | }); 207 | 208 | describe('strip dir', function() { 209 | var res = [ 210 | '/Users/myself/Projects/packman/web_modules/angular-ui-bootstrap/template/popover/popover.html', 211 | 'W:\\Projects\\packman\\web_modules\\angular-ui-bootstrap\\template\\popover\\popover.html', 212 | ]; 213 | 214 | it('#should strip last dir', function() { 215 | expect(run(res[0], '*/dir1/*//')).to.equal('web_modules/dir1/template/popover.html'); 216 | expect(run(res[0], '/*/dir1/*//')).to.equal('/web_modules/dir1/template/popover.html'); 217 | expect(run(res[1], '*/dir1/*//')).to.equal('web_modules/dir1/template/popover.html'); 218 | expect(run(res[1], '/*/dir1/*//')).to.equal('/web_modules/dir1/template/popover.html'); 219 | }); 220 | it('#should strip first dir', function() { 221 | expect(run(res[0], '//dir1/*/*/')).to.equal('/dir1/template/popover/popover.html'); 222 | expect(run(res[1], '//dir1/*/*/')).to.equal('/dir1/template/popover/popover.html'); 223 | }); 224 | it('#should strip middle and last dir', function() { 225 | expect(run(res[0], '*/dir1//*//')).to.equal('packman/dir1/template/popover.html'); 226 | expect(run(res[0], '/*/dir1//*//')).to.equal('/packman/dir1/template/popover.html'); 227 | expect(run(res[1], '*/dir1//*//')).to.equal('packman/dir1/template/popover.html'); 228 | expect(run(res[1], '/*/dir1//*//')).to.equal('/packman/dir1/template/popover.html'); 229 | }); 230 | }); 231 | 232 | describe('strip dir (Win style)', function() { 233 | var res = [ 234 | '/Users/myself/Projects/packman/web_modules/angular-ui-bootstrap/template/popover/popover.html', 235 | 'W:\\Projects\\packman\\web_modules\\angular-ui-bootstrap\\template\\popover\\popover.html', 236 | ]; 237 | 238 | it('#should strip last dir', function() { 239 | expect(run(res[0], '*\\dir1\\*\\\\')).to.equal('web_modules/dir1/template/popover.html'); 240 | expect(run(res[0], '\\*\\dir1\\*\\\\')).to.equal('/web_modules/dir1/template/popover.html'); 241 | expect(run(res[1], '*\\dir1/*\\\\')).to.equal('web_modules/dir1/template/popover.html'); 242 | expect(run(res[1], '\\*\\dir1\\*\\\\')).to.equal('/web_modules/dir1/template/popover.html'); 243 | }); 244 | it('#should strip first dir', function() { 245 | expect(run(res[0], '\\\\dir1\\*\\*\\')).to.equal('/dir1/template/popover/popover.html'); 246 | expect(run(res[1], '\\\\dir1\\*\\*\\')).to.equal('/dir1/template/popover/popover.html'); 247 | }); 248 | it('#should strip middle and last dir', function() { 249 | expect(run(res[0], '*\\dir1\\\\*\\\\')).to.equal('packman/dir1/template/popover.html'); 250 | expect(run(res[0], '\\*\\dir1\\\\*\\\\')).to.equal('/packman/dir1/template/popover.html'); 251 | expect(run(res[1], '*\\dir1\\\\*\\\\')).to.equal('packman/dir1/template/popover.html'); 252 | expect(run(res[1], '\\*\\dir1\\\\*\\\\')).to.equal('/packman/dir1/template/popover.html'); 253 | }); 254 | }); 255 | 256 | describe('cross take from path', function() { 257 | var res = [ 258 | '/Users/myself/Projects/packman/web_modules/angular-ui-bootstrap/template/popover/popover.html', 259 | 'W:\\Projects\\packman\\web_modules\\angular-ui-bootstrap\\template\\popover\\popover.html', 260 | ]; 261 | it('#should be same', function() { 262 | expect(run(res[0], '/**')).to.equal(res[0]); 263 | expect(run(res[0], '**')).to.equal(res[0].replace(/^\//, '')); 264 | expect(run(res[1], '**')).to.equal(res[1].replace(/\\/g, '/')); 265 | }); 266 | it('#should strip first chunk', function() { 267 | expect(run(res[0], '//**')) 268 | .to.equal('/myself/Projects/packman/web_modules/angular-ui-bootstrap/template/popover/popover.html'); 269 | expect(run(res[1], '//**')) 270 | .to.equal('/Projects/packman/web_modules/angular-ui-bootstrap/template/popover/popover.html'); 271 | }); 272 | }); 273 | 274 | describe('relative root and full extend', function() { 275 | var prefs = [ 276 | 'Projects/packman:**', 277 | 'Projects/packman/:**', 278 | 'Projects/packman/:/**', 279 | 'Projects/packman/:/**/', 280 | 'Projects/packman:/**', 281 | 'Projects/packman:/**/', 282 | 'Projects/packman:[dirs]', 283 | 'Projects/packman/:[dirs]', 284 | 'Projects/packman/:/[dirs]', 285 | 'Projects/packman/:/[dirs]/', 286 | 'Projects/packman:/[dirs]', 287 | 'Projects/packman:/[dirs]/', 288 | 'Projects\\packman:**', 289 | 'Projects\\packman\\:**', 290 | 'Projects\\packman\\:\\**', 291 | 'Projects\\packman\\:\\**\\', 292 | 'Projects\\packman:\\**', 293 | 'Projects\\packman:\\**\\', 294 | 'Projects\\packman:[dirs]', 295 | 'Projects\\packman\\:[dirs]', 296 | 'Projects\\packman\\:\\[dirs]', 297 | 'Projects\\packman\\:\\[dirs]\\', 298 | 'Projects\\packman:\\[dirs]', 299 | 'Projects\\packman:\\[dirs]\\', 300 | ]; 301 | var sample = function(res, pref) { 302 | pref = pref.replace(/\\/g, '/').split(':'); 303 | res = res.replace(/\\/g, '/').split(pref.shift()).pop(); 304 | 305 | var path = pref[0][0] === '/' ? 306 | res.replace(/^\/?/, '/') : 307 | res.replace(/^\//, ''); 308 | return path; 309 | }; 310 | 311 | it('#should extend', function() { 312 | prefs.forEach(function(pref) { 313 | resources.forEach(function(res) { 314 | expect(run(res, pref)).to.equal(sample(res, pref)); 315 | }); 316 | }); 317 | }); 318 | }); 319 | 320 | describe('absolute root and full extend', function() { 321 | var sample = function(res, pref) { 322 | var root; 323 | var path; 324 | 325 | root = pref.replace(/\\/g, '/').split(':'); 326 | pref = root.pop(); 327 | root = root.join(':'); 328 | res = res.replace(/\\/g, '/').split(root).pop(); 329 | path = pref[0][0] === '/' ? 330 | res.replace(/^\/?/, '/') : 331 | res.replace(/^\//, ''); 332 | return path; 333 | }; 334 | 335 | it('#should extend', function() { 336 | var resources = [ 337 | '/Users/myself/Projects/packman/web_modules/angular-ui-bootstrap/template/popover/popover.html', 338 | '/Users/myself/Projects/packman/components/article/actions/actions.html', 339 | ]; 340 | [ 341 | '/Users/myself/Projects/packman:**', 342 | '/Users/myself/Projects/packman/:**', 343 | '/Users/myself/Projects/packman/:/**', 344 | '/Users/myself/Projects/packman/:/**/', 345 | '/Users/myself/Projects/packman:/**', 346 | '/Users/myself/Projects/packman:/**/', 347 | '/Users/myself/Projects/packman:[dirs]', 348 | '/Users/myself/Projects/packman/:[dirs]', 349 | '/Users/myself/Projects/packman/:/[dirs]', 350 | '/Users/myself/Projects/packman/:/[dirs]/', 351 | '/Users/myself/Projects/packman:/[dirs]', 352 | '/Users/myself/Projects/packman:/[dirs]/', 353 | ].forEach(function(pref) { 354 | resources.forEach(function(res) { 355 | expect(run(res, pref)).to.equal(sample(res, pref)); 356 | }); 357 | }); 358 | }); 359 | 360 | it('#should extend (Win style)', function() { 361 | resources = [ 362 | 'W:\\Projects\\packman\\web_modules\\angular-ui-bootstrap\\template\\popover\\popover.html', 363 | 'W:\\Projects\\packman\\components\\article\\actions\\actions.html', 364 | ]; 365 | [ 366 | 'W:\\Projects\\packman:**', 367 | 'W:\\Projects\\packman\\:**', 368 | 'W:\\Projects\\packman\\:\\**', 369 | 'W:\\Projects\\packman\\:\\**\\', 370 | 'W:\\Projects\\packman:\\**', 371 | 'W:\\Projects\\packman:\\**\\', 372 | 'W:\\Projects\\packman:[dirs]', 373 | 'W:\\Projects\\packman\\:[dirs]', 374 | 'W:\\Projects\\packman\\:\\[dirs]', 375 | 'W:\\Projects\\packman\\:\\[dirs]\\', 376 | 'W:\\Projects\\packman:\\[dirs]', 377 | 'W:\\Projects\\packman:\\[dirs]\\', 378 | ].forEach(function(pref) { 379 | resources.forEach(function(res) { 380 | expect(run(res, pref)).to.equal(sample(res, pref)); 381 | }); 382 | }); 383 | }); 384 | }); 385 | 386 | describe('file name pattern', function() { 387 | var params = { 388 | resource: 'template/popover/popover.html', 389 | }; 390 | 391 | it('#should strip extension', function() { 392 | params.query = '?name=[name]'; 393 | expect(lib.call(params)).to.equal('popover'); 394 | params.query += '&prefix=*/*'; 395 | expect(lib.call(params)).to.equal('template/popover/popover'); 396 | }); 397 | 398 | it('#should replace extension', function() { 399 | params.query = '?name=[name].tpl'; 400 | expect(lib.call(params)).to.equal('popover.tpl'); 401 | params.query += '&prefix=*/*'; 402 | expect(lib.call(params)).to.equal('template/popover/popover.tpl'); 403 | }); 404 | 405 | it('#should swap name and extension', function() { 406 | params.query = '?name=[ext].[name]'; 407 | expect(lib.call(params)).to.equal('html.popover'); 408 | params.query += '&prefix=*/*'; 409 | expect(lib.call(params)).to.equal('template/popover/html.popover'); 410 | }); 411 | 412 | it('#should swap name and extension', function() { 413 | params.query = '?name=[ext].[name]'; 414 | expect(lib.call(params)).to.equal('html.popover'); 415 | params.query += '&prefix=*/*'; 416 | expect(lib.call(params)).to.equal('template/popover/html.popover'); 417 | }); 418 | 419 | it('#should append suffix', function() { 420 | params.query = '?name=[name]-foo.[ext]'; 421 | expect(lib.call(params)).to.equal('popover-foo.html'); 422 | }); 423 | 424 | it('#should replace name with literal', function() { 425 | params.query = '?name=foo'; 426 | expect(lib.call(params)).to.equal('foo'); 427 | }); 428 | 429 | it('#should ignore invalid name pattern', function() { 430 | params.query = '?name=[name].[ext].[ext]'; 431 | expect(lib.call(params)).to.equal('popover.html'); 432 | params.query += '&prefix=*/*'; 433 | expect(lib.call(params)).to.equal(params.resource); 434 | }); 435 | }); 436 | 437 | describe('module id pattern', function() { 438 | var params = { 439 | resource: 'template/popover/popover.html' 440 | }; 441 | 442 | it('#should replace root', function() { 443 | templateId = 'some/popover.html'; 444 | params.query = '?name=[file].[ext]&module=web.[root]'; 445 | expect(moduleLib.call(params, templateId)).to.deep.equal({moduleId: 'web.some', templateId: 'popover.html'}); 446 | }); 447 | 448 | it('#should replace nothing', function() { 449 | templateId = 'some/popover.html'; 450 | params.query = '?name=[file].[ext]&module=some'; 451 | expect(moduleLib.call(params, templateId)).to.deep.equal({moduleId: 'some', templateId: 'some/popover.html'}); 452 | }); 453 | 454 | it('#should be ng by default', function() { 455 | templateId = 'some/popover.html'; 456 | params.query = '?name=[file].[ext]'; 457 | expect(moduleLib.call(params, templateId)).to.deep.equal({moduleId: 'ng', templateId: 'some/popover.html'}); 458 | }); 459 | }); 460 | 461 | describe('various casese', function() { 462 | var resources = [ 463 | '/Users/myself/Projects/packman/web_modules/angular-ui-bootstrap/template/popover/popover.html', 464 | 'W:\\Projects\\packman\\web_modules\\angular-ui-bootstrap\\template\\popover\\popover.html', 465 | ]; 466 | it('#should extend, replace, strip and take', function() { 467 | resources.forEach(function(res) { 468 | expect(run(res, 'packman:**/dir1//*')).to.equal('web_modules/dir1/popover/popover.html'); 469 | expect(run(res, 'packman:*/dir1/**')).to.equal('web_modules/dir1/template/popover/popover.html'); 470 | expect(run(res, 'packman:*//**')).to.equal('web_modules/template/popover/popover.html'); 471 | expect(run(res, 'packman:/**/dir1//')).to.equal('/web_modules/angular-ui-bootstrap/dir1/popover.html'); 472 | }); 473 | }); 474 | it('#should convert second `**` to `*`', function() { 475 | resources.forEach(function(res) { 476 | expect(run(res, 'packman:**/dir1//**')).to.equal('web_modules/dir1/popover/popover.html'); 477 | expect(run(res, 'packman:/**/dir1/**')) 478 | .to.equal('/web_modules/angular-ui-bootstrap/dir1/popover/popover.html'); 479 | }); 480 | }); 481 | }); 482 | 483 | describe('test root prefix', function() { 484 | var resources = [ 485 | '/Users/myself/Projects/packman/web_modules/angular-ui-bootstrap/partials/foo/foo.html', 486 | '/Users/myself/Projects/packman/web_modules/angular-ui-bootstrap/partials/template.html', 487 | 'W:\\Projects\\packman\\web_modules\\angular-ui-bootstrap\\partials\\another_template.html', 488 | ]; 489 | it('#should not have leading slash template in subfolder of root folder', function() { 490 | expect(run(resources[0], 'partials:**')).to.equal('foo/foo.html'); 491 | }); 492 | 493 | it('#should not have leading slash for template in root folder', function() { 494 | resources.forEach(function(res) { 495 | expect(run(resources[1], 'partials:**')).to.equal('template.html'); 496 | }); 497 | }); 498 | 499 | it('#[win] should not have leading slash for template in root folder', function() { 500 | resources.forEach(function(res) { 501 | expect(run(resources[2], 'partials:**')).to.equal('another_template.html'); 502 | }); 503 | }); 504 | }); 505 | }); 506 | -------------------------------------------------------------------------------- /test/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | 3 | var minimizeOptions = JSON.stringify({ 4 | removeComments: true, 5 | removeCommentsFromCDATA: true, 6 | collapseWhitespace: true, 7 | conservativeCollapse: false, 8 | preserveLineBreaks: true, 9 | removeEmptyAttributes: true, 10 | keepClosingSlash: true, 11 | }); 12 | 13 | module.exports = { 14 | context: __dirname, 15 | entry: path.resolve(__dirname, 'entry.js'), 16 | output: { 17 | path: path.resolve(__dirname, 'out'), 18 | filename: '[name].out.js', 19 | }, 20 | module: { 21 | loaders: [ 22 | { 23 | test: /\.html$/, 24 | loader: '../index.js?prefix=grot/[dir]//[dir]//tmpl&module=appModule&name=[name].tpl&-exportId' + 25 | '&minimizeOptions=' + minimizeOptions + '&conservativeCollapse', 26 | }, 27 | ], 28 | }, 29 | }; 30 | -------------------------------------------------------------------------------- /test/webpack2.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | 3 | module.exports = { 4 | context: __dirname, 5 | entry: path.resolve(__dirname, 'entry.js'), 6 | output: { 7 | path: path.resolve(__dirname, 'out'), 8 | filename: '[name].out.js', 9 | }, 10 | module: { 11 | rules: [{ 12 | test: /\.html$/, 13 | use:[{ 14 | loader: '../index.js', 15 | options: { 16 | prefix: 'grot/[dir]//[dir]//tmpl', 17 | module: 'appModule', 18 | name: '[name].tpl', 19 | exportId: false, 20 | minimizeOptions: { 21 | removeComments: true, 22 | removeCommentsFromCDATA: true, 23 | collapseWhitespace: true, 24 | conservativeCollapse: false, 25 | preserveLineBreaks: true, 26 | removeEmptyAttributes: true, 27 | keepClosingSlash: true, 28 | }, 29 | }, 30 | }], 31 | }], 32 | }, 33 | }; 34 | --------------------------------------------------------------------------------