http-server优化默认列表展示

Published on 2025-03-06 11:22 in 分类: 软件 with 狂盗一枝梅
分类: 软件

node安装好http-server模块后,通过http-server .命令浏览器默认展示效果如下:

image-20250306105233951

个人觉得挺丑的,忍不了一点,我想改一改其CSS样式,优化下展示效果,但是找了半天网上竟然没有教程。。。。没办法,硬着头皮找了半天代码,终于找到了在哪里修改

第一步:找到http-server安装目录

我使用的nvm管理多个node版本,使用nvm root命令可以看到nvm的安装目录,全局安装的node module都在对应的版本下的node文件夹中。

image-20250306105626483

若是直接安装的node,可以使用命令npm root -g 查看全局package安装的位置。

第二步:修改css样式

打开node_modules\http-server\lib\core\show-dir文件夹,修改styles.js文件,复制如下内容覆盖styles.js文件

'use strict';

const icons = require('./icons.json');

const IMG_SIZE = 16;

let css = `i.icon { display: block; height: ${IMG_SIZE}px; width: ${IMG_SIZE}px; }\n`;
css += 'table tr { white-space: nowrap; line-height: 30px;color:rgb(68, 68, 68);}\n';
css += 'td.perms {}\n';
css += 'td.file-size { text-align: right; padding-left: 1em; }\n';
css += 'td.display-name { padding-left: 1em; }\n';
css += '.displayName{text-decoration: none;cursor: pointer;}';
css += 'a{color:rgb(68, 68, 68);}';
css += 'a:hover{color:black;font-weight:bold;}';

Object.keys(icons).forEach((key) => {
  css += `i.icon-${key} {\n`;
  css += `  background-image: url("data:image/png;base64,${icons[key]}");\n`;
  css += '}\n\n';
});

exports.icons = icons;
exports.css = css;

第三步:修改默认显示模板

打开node_modules\http-server\lib\core\show-dir文件夹,修改index.js文件,复制如下内容覆盖index.js文件

'use strict';

const styles = require('./styles');
const lastModifiedToString = require('./last-modified-to-string');
const permsToString = require('./perms-to-string');
const sizeToString = require('./size-to-string');
const sortFiles = require('./sort-files');
const fs = require('fs');
const path = require('path');
const he = require('he');
const etag = require('../etag');
const url = require('url');
const status = require('../status-handlers');

const supportedIcons = styles.icons;
const css = styles.css;

module.exports = (opts) => {
  // opts are parsed by opts.js, defaults already applied
  const cache = opts.cache;
  const root = path.resolve(opts.root);
  const baseDir = opts.baseDir;
  const humanReadable = opts.humanReadable;
  const hidePermissions = opts.hidePermissions;
  const handleError = opts.handleError;
  const showDotfiles = opts.showDotfiles;
  const si = opts.si;
  const weakEtags = opts.weakEtags;

  return function middleware(req, res, next) {
    // Figure out the path for the file from the given url
    const parsed = url.parse(req.url);
    const pathname = decodeURIComponent(parsed.pathname);
    const dir = path.normalize(
      path.join(
        root,
        path.relative(
          path.join('/', baseDir),
          pathname
        )
      )
    );

    fs.stat(dir, (statErr, stat) => {
      if (statErr) {
        if (handleError) {
          status[500](res, next, { error: statErr });
        } else {
          next();
        }
        return;
      }

      // files are the listing of dir
      fs.readdir(dir, (readErr, _files) => {
        let files = _files;

        if (readErr) {
          if (handleError) {
            status[500](res, next, { error: readErr });
          } else {
            next();
          }
          return;
        }

        // Optionally exclude dotfiles from directory listing.
        if (!showDotfiles) {
          files = files.filter(filename => filename.slice(0, 1) !== '.');
        }

        res.setHeader('content-type', 'text/html');
        res.setHeader('etag', etag(stat, weakEtags));
        res.setHeader('last-modified', (new Date(stat.mtime)).toUTCString());
        res.setHeader('cache-control', cache);
        function render(dirs, renderFiles, lolwuts) {
          // each entry in the array is a [name, stat] tuple

		  var dispayPathname = pathname;
		  if(dispayPathname.length>=3){
			dispayPathname = pathname.substring(1,pathname.length-1)
		  }
          let html = `${[
            '<!doctype html>',
            '<html>',
            '  <head>',
            '    <meta charset="utf-8">',
            '    <meta name="viewport" content="width=device-width">',
            `    <title>${he.encode(dispayPathname)}</title>`,
            `    <style type="text/css">${css}</style>`,
            '  </head>',
            '  <body>',
            `<h1>${he.encode(dispayPathname)}</h1>`,
          ].join('\n')}\n`;

          html += '<table>';

          const failed = false;
          const writeRow = (file) => {
            // render a row given a [name, stat] tuple
            const isDir = file[1].isDirectory && file[1].isDirectory();
            let href = `./${encodeURIComponent(file[0])}`;

            // append trailing slash and query for dir entry
            if (isDir) {
              href += `/${he.encode((parsed.search) ? parsed.search : '')}`;
            }

            const displayName = he.encode(file[0]) + ((isDir) ? '/' : '');
            const ext = file[0].split('.').pop();
            const classForNonDir = supportedIcons[ext] ? ext : '_page';
            const iconClass = `icon-${isDir ? '_blank' : classForNonDir}`;
			
            // TODO: use stylessheets?
            html += `${'<tr class="customTr">' +
              '<td><i class="icon '}${iconClass}"></i></td>`;
            if (!hidePermissions) {
              html += `<td class="perms"><code>(${permsToString(file[1])})</code></td>`;
            }
            html +=
              `<td class="last-modified">${lastModifiedToString(file[1])}</td>` +
              `<td class="file-size"><code>${sizeToString(file[1], humanReadable, si)}</code></td>`;
			  if(isDir){
				html+=`<td class="display-name"><a class="displayName" href="${href}">${displayName}</a></td>`;  
			  }else{
				  var displayName1  = displayName;
				  if(validationEnd(displayName,".html")){
					  displayName1= displayName.substring(0,displayName.length-5);
				  }
				html+=`<td class="display-name"><a class="displayName" href="${href}" target="_blank">${displayName1}</a></td>`;  
			  }
              
              html +='</tr>\n';
          };

          dirs.sort((a, b) => a[0].toString().localeCompare(b[0].toString())).forEach(writeRow);
          renderFiles.sort((a, b) => a.toString().localeCompare(b.toString())*-1).forEach(writeRow);
          lolwuts.sort((a, b) => a[0].toString().localeCompare(b[0].toString())).forEach(writeRow);

          

          if (!failed) {
            res.writeHead(200, { 'Content-Type': 'text/html' });
            res.end(html);
          }
        }

		function validationEnd (str, appoint) {
		   str=str.toLowerCase();  //不区分大小写:全部转为小写后进行判断
				
		   var start = str.length-appoint.length;  //相差长度=字符串长度-特定字符长度
		   var char= str.substr(start,appoint.length);//将相差长度作为开始下标,特定字符长度为截取长度
			
		   if(char== appoint){ //两者相同,则代表验证通过
			  return true;
		   }
		   return false;
		}

        sortFiles(dir, files, (lolwuts, dirs, sortedFiles) => {
          // It's possible to get stat errors for all sorts of reasons here.
          // Unfortunately, our two choices are to either bail completely,
          // or just truck along as though everything's cool. In this case,
          // I decided to just tack them on as "??!?" items along with dirs
          // and files.
          //
          // Whatever.

          // if it makes sense to, add a .. link
          if (path.resolve(dir, '..').slice(0, root.length) === root) {
            fs.stat(path.join(dir, '..'), (err, s) => {
              if (err) {
                if (handleError) {
                  status[500](res, next, { error: err });
                } else {
                  next();
                }
                return;
              }
              dirs.unshift(['..', s]);
              render(dirs, sortedFiles, lolwuts);
            });
          } else {
            render(dirs, sortedFiles, lolwuts);
          }
        });
      });
    });
  };
};

第四步:修改日期展示

打开node_modules\http-server\lib\core\show-dir文件夹,修改last-modified-to-string.js文件,复制如下内容覆盖last-modified-to-string.js文件

'use strict';

Date.prototype.format = function(format)
{
 var o = {
 "M+" : this.getMonth()+1, //month
 "d+" : this.getDate(),    //day
 "h+" : this.getHours(),   //hour
 "m+" : this.getMinutes(), //minute
 "s+" : this.getSeconds(), //second
 "q+" : Math.floor((this.getMonth()+3)/3),  //quarter
 "S" : this.getMilliseconds() //millisecond
 }
 if(/(y+)/.test(format)) format=format.replace(RegExp.$1,
 (this.getFullYear()+"").substr(4 - RegExp.$1.length));
 for(var k in o)if(new RegExp("("+ k +")").test(format))
 format = format.replace(RegExp.$1,
 RegExp.$1.length==1 ? o[k] :
 ("00"+ o[k]).substr((""+ o[k]).length));
 return format;
}

module.exports = function lastModifiedToString(stat) {
  const t = new Date(stat.mtime);
  return t.format('yyyy-MM-dd hh:mm:ss');
};

最后:效果展示

首页:

image-20250306112018699

点击进入子目录:

image-20250306112110418

END.


#node #npm
复制 复制成功