vscode插件liveserver增加对thymeleaf模板的简单支持

  • vscode插件liveserver增加对thymeleaf模板的简单支持已关闭评论
  • 76 次浏览
  • A+
所属分类:Web前端
摘要

vscode+liveserver开发时,多个页面引用的公用静态资源在每个页面都写一个遍比较麻烦,想让liveserver支持简单的thymeleaf语法,只要能把公用资源抽出来单独放到一个文件中声明即可。


vscode插件liveserver增加对thymeleaf模板的简单支持

背景

vscode+liveserver开发时,多个页面引用的公用静态资源在每个页面都写一个遍比较麻烦,想让liveserver支持简单的thymeleaf语法,只要能把公用资源抽出来单独放到一个文件中声明即可。

网上找了一下,没有现成的功能,为方便自己使用,修改了一个liveserver插件。

其它人也可能会遇到同样的需求,这里把代码贴出来

实用方式

只有两个简单的js文件,同时简单修改一下liveserver插件的index.js文件即可

liveserver插件的位置:
C:Users*.vscodeextensionsritwickdey.liveserver-5.7.9node_moduleslive-server(具体路径,由于机器配置以及使用的liveserver版不同,可能不一样)

  1. thymeleaf-handler.jsthymeleaf-parser.js拷到插件目录中的live-server目录中
  2. 修改index.js文件

liveserver目录结构:

vscode插件liveserver增加对thymeleaf模板的简单支持

项目结构

include.html

vscode插件liveserver增加对thymeleaf模板的简单支持

  • env.txt 用于放置环境变里,在页面中可使用th:text来引用
  • include.html 用于放置公共引用,仅支持th:fragment

index.html

vscode插件liveserver增加对thymeleaf模板的简单支持

env.txt

vscode插件liveserver增加对thymeleaf模板的简单支持

输出到浏览器的结果

vscode插件liveserver增加对thymeleaf模板的简单支持

源码

//index.js  var fs = require('fs'), 	connect = require('connect'), 	serveIndex = require('serve-index'), 	logger = require('morgan'), 	WebSocket = require('faye-websocket'), 	path = require('path'), 	url = require('url'), 	http = require('http'), 	send = require('send'), 	open = require('opn'), 	es = require("event-stream"), 	os = require('os'), 	chokidar = require('chokidar'), 	httpProxy = require('http-proxy'), 	HandlerStream = require('./thymeleaf-handler');//这里增加一行对thymeleaf-handler的引用       ......       //在后面找到inject函数     function inject(stream) { 			if (injectTag) { 				// We need to modify the length given to browser 				var len = GET_INJECTED_CODE().length + res.getHeader('Content-Length'); 				res.setHeader('Content-Length', len); 				var originalPipe = stream.pipe; 				stream.pipe = function (resp) { 					originalPipe.call(stream, es.replace(new RegExp(injectTag, "i"), GET_INJECTED_CODE() + injectTag)) 					.pipe(new HandlerStream(root,res)).pipe(resp);// 修改这一句,把原来的 .pipe(resp) 修改为 .pipe(new HandlerStream(root,res)).pipe(resp); 				}; 			} 		} 

以下为thymeleaf-handler.jsthymeleaf-parser.js的源码

//thymeleaf-handler  const fs = require('fs'); const path = require('path') const stream = require('stream'); let thymeleafParser = require("./thymeleaf-parser");   class HandlerStream extends stream.Transform{     constructor (root,res) {         super();              this.root = root;            this.body = "";         this.res = res;         this.byteLen = 0;     }      _parse(){         return thymeleafParser(this.root,this.body);     }      _transform (chunk, encoding, callback){         this.body += chunk;         this.byteLen += chunk.byteLength;         callback()     }      _getBufferLen(v){         const buf = Buffer.from(v, 'utf8');                         return buf.length;       }      _flush (callback){                 let newBoday = this._parse();                 let newLen = this._getBufferLen(newBoday);         var len = (newLen - this.byteLen) + this.res.getHeader('Content-Length');         this.res.setHeader('Content-Length', len);                 this.push(newBoday);         callback();     } }     module.exports = HandlerStream;  
//thymeleaf-parser const fs = require('fs'); const path = require('path');   class Fragment{     constructor(name,content){         this.paramName = null;         this.name = null;          this.decodeName(name);          //替换对上下文件的引用         this.content = content.replace("[[@{/}]]","/");          let parser = new Parser(this.content);          parser.parseSrc()         .parseHref();          this.content = parser.value;     }      decodeName(name){         let r = /"?(.+?)((.+))"?/;         let m = r.exec(name);         if(m){             this.name = m[1];             this.paramName = m[2];         }         else if(/"(.+)"/.test(name)){                     this.name = name.slice(1,-1);         }         else             this.name = name;     }       getContent(param){         if(param && this.paramName){             return this.content.replace(`${${this.paramName}}`,param)         }                 else             return this.content;      }  }  class Parser{     constructor(value){         this.value = value;     }     parseSrc(){         this.value = this.value.replace(/th:src="@{(.+?)}"/g,'src="$1"');          return this;     }      parseHref(){         this.value = this.value.replace(/th:href="@{(.+?)}"/g,'href="$1"');          return this;     }      parseText(env){         let reg = /<(div|a|input|span|button|p|title)(.*?) th:text="(.+?)"(.*?)></1>/g;          let textBlocks = [];          let m = reg.exec(this.value);         while(m){             m[0];             m[2];             textBlocks.push({                 tagContent: m[0],                 tagName: m[1],                 attrs:[m[2],m[4]],                 value: m[3]             });              m = reg.exec(this.value);         }           reg = /${(.+)}/;          for(let b of textBlocks){             m = reg.exec(b.value);             if(m && env.getValue(m[1])){                 b.value = env.getValue(m[1]);             }                          let tag = `<${b.tagName}${b.attrs[0]}${b.attrs[1]}>${b.value}</${b.tagName}>`;             this.value = this.value.replace(b.tagContent,tag);                     }          return this;     }      parseBlock(fragments){               function removeBrackets(v){             if(!v) return v;                          let m = /('(.+)')/.exec(v);             if(m){                 return m[1];             }             else{                 return "";             }         }         //<th:block th:include="include :: header('示例')"/>         let reg = /<th:block th:include="includes*::s*([a-zA-z0-9_]+?)((.+))?"s*/>/g;           let blocks = [];          let m = reg.exec(this.value);         while(m){                      blocks.push({                 tag: m[0],                 name: m[1],                 param: removeBrackets(m[2])             });             m = reg.exec(this.value);         }           for(let block of blocks){             let fragment = fragments[block.name];             if(fragment){                 this.value = this.value.replace(block.tag,fragment.getContent(block.param));             }                   }         return this;     } }  class Evn{     constructor(){         this.values = {};     }      load(root){                 let envString = readFile(path.resolve(root,"env.txt"))          let lines = envString.split('n');          let r = /(.+?)=(.+)/;          for(let l of lines){             l = l.trim();             if(l.startsWith("#") || !l) continue;              let m = r.exec(l);             if(m){                 this.values[m[1].trim()] = m[2].trim();             }                        }     }      getValue(key){         if(this.values[key]){             return this.values[key];         }         else             return null;     }  }  function parseTemplate(template){{     let fragmentReg = /<(div|head|section)s+th:fragment=(.*?)>(.*?)</1>/gs;      let fragments = {};      let m = fragmentReg.exec(template);      while(m){         let fragment = new Fragment(m[2],m[3]);         fragments[fragment.name] = fragment;               m = fragmentReg.exec(template);     }      return fragments; }}  function readFile(fileName){     if(fs.existsSync(fileName)){         return fs.readFileSync(fileName).toString("utf8");     }     else         return ""; }  function readTemplate(root){         return readFile(path.resolve(root,"include.html")); }  function parse(root,html){          let fragments = parseTemplate(readTemplate(root));      let env = new Evn();     env.load(root);       let parser = new Parser(html);      parser.parseSrc()     .parseHref()     .parseBlock(fragments)     .parseText(env);       return parser.value; }    module.exports = parse