// This plugin to Meteor uses the linter plugin api to package up all the templates indexed by name into a single file saved in the /private folder in the project. // The file is intended to be used to service search engine requests for static html by utilizing server side rendering of the templates. // Meteor packages up all the content not in /private or /public, so simply accessing the templates at runtime on the server does not appear to be an option. const fs = Npm.require('fs'); const path = Npm.require('path'); //Disabled linter for now. Supposedly Google at least can manage SEO without server side rendering. //Plugin.registerLinter({ // extensions: ["html"] // //filenames: [".jshintrc"] //}, () => new S3); class S3 { constructor() { this.templateStart = //; this.templateEnd = /<\/\s*template\s*>\s*/; } extractTemplate(html, map) { try { let result = html.match(this.templateStart); if(result != null) { let name = result[2]; html = html.substring(result.index + result[0].length); result = html.match(this.templateEnd); //console.log("Matching: \n" + html); //console.log("\n" + result); if(result != null) { let contents = html.substring(0, result.index); html = html.substring(result.index + result[0].length); //Save the template contents indexed by its name. //TODO: Warn if we overwrite any template names??? Should never happen unless the developer made an error in naming. map[name] = contents; //console.log("Found template: " + name); //console.log(contents); } else html = null; } else html = null; } catch(err) { console.log(err); html = null; } return html; } processFilesForPackage(files, options) { try { let map = {}; //let fileNames = []; let _this = this; let originalContents = fs.readFileSync('private/template-index', {encoding: 'utf8', flag: 'r'}); let counter = 0; //Extract all templates for every file processed (all HTML files). files.forEach((file) => { if(file._source.relPath.startsWith("imports/")) { /// && file._source.relPath === "imports/ui/Test.html" let html = file.getContentsAsString(); while(html != null) { //Will return null if no more templates are to be found. html = this.extractTemplate(html, map); } } }); //Returns a 16 character hex hash that is zero padded. let hashString = (str)=> { let hash = 0; if(str.length === 0) return hash; for(let i = 0; i < str.length; i++) { let chr = str.charCodeAt(i); hash = ((hash << 5) - hash) + chr; hash |= 0; // Convert to 32bit integer } return ("0000000000000000" + hash.toString(16)).substr(-16); }; let output = JSON.stringify(map); //console.log("Out: " + output); let hash = hashString(output); //console.log("Hash: " + hash); let originalHash = hashString(originalContents); //console.log(originalHash); if(originalHash !== hash) { //console.log("Hash does not match!"); //Write the mapping to a 'template-index' file in the private folder. fs.writeFile('private/template-index', output); } else { //console.log("Hash matches.."); } } catch(err) { console.log(err); } } }