├── .gitignore
├── ss.png
├── example
├── outer
│ └── msg.png
├── public
│ ├── msg.png
│ ├── msg.js
│ ├── msg.css
│ ├── index.html
│ └── dir
│ │ └── default.html
├── .eslintrc.json
└── test.js
├── .eslintrc.json
├── lib
├── .eslintrc.json
└── node-static-alias.js
├── package.json
├── LICENSE
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode
2 | node_modules
3 |
--------------------------------------------------------------------------------
/ss.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anseki/node-static-alias/HEAD/ss.png
--------------------------------------------------------------------------------
/example/outer/msg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anseki/node-static-alias/HEAD/example/outer/msg.png
--------------------------------------------------------------------------------
/example/public/msg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anseki/node-static-alias/HEAD/example/public/msg.png
--------------------------------------------------------------------------------
/example/public/msg.js:
--------------------------------------------------------------------------------
1 |
2 | document.getElementById('js-msg').innerHTML = 'Hello world! from [public/msg.js]';
3 |
4 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "extends": "../../_common/files/eslintrc.json",
4 | "env": {"node": true}
5 | }
6 |
--------------------------------------------------------------------------------
/example/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "no-var": "off",
4 | "prefer-arrow-callback": "off",
5 | "object-shorthand": "off"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/lib/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "no-var": "off",
4 | "prefer-arrow-callback": "off",
5 | "no-underscore-dangle": [2, {"allow": ["_log"]}]
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/example/public/msg.css:
--------------------------------------------------------------------------------
1 |
2 | #css-msg {
3 | font-size: 0;
4 | }
5 |
6 | #css-msg:before {
7 | content: 'Hello world! from [public/msg.css]';
8 | font-size: 16px;
9 | }
10 |
11 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node-static-alias",
3 | "version": "1.1.2",
4 | "title": "node-static-alias",
5 | "description": "Serve static file which is not requested file. (e.g. `file.min.js` is requested, serve `file.js`)",
6 | "keywords": [
7 | "http",
8 | "httpd",
9 | "test",
10 | "static",
11 | "file",
12 | "server",
13 | "alias",
14 | "mod_rewrite",
15 | "directoryindex",
16 | "min",
17 | "log"
18 | ],
19 | "main": "./lib/node-static-alias.js",
20 | "files": [
21 | "lib/!(.eslintrc.json)",
22 | "example/!(.eslintrc.json)",
23 | "ss.png"
24 | ],
25 | "engines": {
26 | "node": ">= 0.8.0"
27 | },
28 | "dependencies": {
29 | "node-static": "~0.7.2"
30 | },
31 | "homepage": "https://github.com/anseki/node-static-alias",
32 | "repository": {
33 | "type": "git",
34 | "url": "git://github.com/anseki/node-static-alias.git"
35 | },
36 | "bugs": "https://github.com/anseki/node-static-alias/issues",
37 | "license": "MIT",
38 | "author": {
39 | "name": "anseki",
40 | "url": "https://github.com/anseki"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 anseki
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.
--------------------------------------------------------------------------------
/example/test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var staticAlias = require('../lib/node-static-alias');
4 |
5 | // var log4js = require('log4js');
6 | // var logger = log4js.getLogger('node-static-alias');
7 | // logger.setLevel(log4js.levels.INFO);
8 |
9 | process.chdir(__dirname);
10 |
11 | var fileServer = new staticAlias.Server('./public', {
12 | alias: [
13 |
14 | // file.min.ext --> file.ext
15 | {
16 | match: /\.min\.(?:js|css)$/,
17 | serve: function(params) {
18 | return params.absDir + '/' + params.basename.replace(/\.min$/, '.') + params.suffix;
19 | }
20 | },
21 |
22 | // outside of document-root
23 | {
24 | match: ['suffix=png', 'suffix=jpg'],
25 | serve: '../outer/<% fileName %>',
26 | allowOutside: true
27 | },
28 |
29 | // directoryIndex
30 | {
31 | match: /\/$/,
32 | serve: '<% absPath %>/default.html'
33 | }
34 |
35 | ],
36 | // logger: logger
37 | logger: console
38 | });
39 |
40 | console.log('START (http://127.0.0.1:8080/)');
41 |
42 | require('http').createServer(function(request, response) {
43 | request.addListener('end', function() {
44 | fileServer.serve(request, response);
45 | }).resume();
46 | }).listen(8080);
47 |
48 |
--------------------------------------------------------------------------------
/example/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | PATH: public/index.html
5 |
6 |
22 |
23 |
24 |
25 | This file: public/index.html (Compare this to the browser's path)
26 |
27 |
28 | Message from CSS (Request: [public/msg.min.css]) (Compare this to the path in message)
29 |
NO message.
30 |
31 |
32 |
33 | Message from JS (Request: [public/msg.min.js]) (Compare this to the path in message)
34 |
NO message.
35 |
36 |
37 |
38 |
39 | Message from IMG (Request: [public/msg.png]) (Compare this to the path in message)
40 |
NO message.
41 |
42 |
43 | To [dir/]
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/example/public/dir/default.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | PATH: public/dir/default.html
5 |
6 |
22 |
23 |
24 |
25 | This file: public/dir/default.html (Compare this to the browser's path)
26 |
27 |
28 | Message from CSS (Request: [public/msg.min.css]) (Compare this to the path in message)
29 |
NO message.
30 |
31 |
32 |
33 | Message from JS (Request: [public/msg.min.js]) (Compare this to the path in message)
34 |
NO message.
35 |
36 |
37 |
38 |
39 | Message from IMG (Request: [public/msg.png]) (Compare this to the path in message)
40 |
NO message.
41 |
42 |
43 | To [../]
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/lib/node-static-alias.js:
--------------------------------------------------------------------------------
1 | /*
2 | * node-static-alias
3 | * https://github.com/anseki/node-static-alias
4 | *
5 | * Copyright (c) 2018 anseki
6 | * Licensed under the MIT license.
7 | */
8 |
9 | 'use strict';
10 |
11 | var staticSuper = require('node-static'),
12 | fs = require('fs'),
13 | events = require('events'),
14 | path = require('path'),
15 | url = require('url'),
16 | querystring = require('querystring'),
17 | platform = process.platform;
18 |
19 | function Server() {
20 | var that = this;
21 | staticSuper.Server.apply(that, arguments); // Super class constructor
22 |
23 | if (that.options.alias) { // To Array
24 | if (!Array.isArray(that.options.alias)) {
25 | that.options.alias = [that.options.alias];
26 | }
27 | that.options.alias.forEach(function(alias) {
28 | alias.match = !alias.match ? [] :
29 | !Array.isArray(alias.match) ? [alias.match] :
30 | alias.match;
31 | alias.serve = !alias.serve ? ['<% absPath %>'] :
32 | !Array.isArray(alias.serve) ? [alias.serve] :
33 | alias.serve;
34 | });
35 | }
36 |
37 | if (that.options.logger) {
38 | ['info', 'log'].some(function(methodName) {
39 | if (typeof that.options.logger[methodName] === 'function') {
40 | that._log = function() {
41 | that.options.logger[methodName].apply(that.options.logger, arguments);
42 | };
43 | return true;
44 | }
45 | return false;
46 | });
47 | }
48 | that._log = that._log || function() {};
49 | }
50 |
51 | // util.inherits()
52 | Server.prototype = Object.create(staticSuper.Server.prototype);
53 | Server.prototype.constructor = Server;
54 |
55 | Server.prototype.servePath = function(pathname, status, headers, req, res, finish) {
56 | var that = this,
57 | servePath = that.parsePath(pathname, req, res),
58 | promise = new events.EventEmitter();
59 |
60 | if (servePath) {
61 | fs.stat(servePath, function(e, stat) {
62 | if (e) {
63 | finish(404, {});
64 | } else if (stat.isFile()) { // Stream a single file.
65 | that.respond(null, status, headers, [servePath], stat, req, res, finish);
66 | } else if (stat.isDirectory()) { // Stream a directory of files.
67 | that.serveDir(servePath, req, res, finish);
68 | } else {
69 | finish(400, {});
70 | }
71 | });
72 | } else {
73 | // Forbidden
74 | finish(403, {});
75 | }
76 | return promise;
77 | };
78 |
79 | Server.prototype.parsePath = function(pathname, req, res) {
80 | var that = this,
81 | params = {absPath: that.resolve(pathname)},
82 | allowOutside = false,
83 | key, query, servePath;
84 |
85 | if (!that.options.alias) { return params.absPath; }
86 |
87 | if (req.headers) {
88 | // The strange HTTP header like a 'reqPath' may come from client. But, ignore it.
89 | for (key in req.headers) {
90 | if (key !== 'absPath') { params[key] = req.headers[key] + ''; }
91 | }
92 | }
93 |
94 | params.reqPath = pathname;
95 | params.reqDir = path.dirname(params.reqPath);
96 | params.absDir = path.dirname(params.absPath);
97 | params.fileName = path.basename(params.reqPath);
98 | // params.suffix = path.extname(params.reqPath).replace(/^\./, '');
99 | params.basename = params.fileName.replace(/^([^.].*)\.([^.]*)$/,
100 | function(s, basename, suffix) {
101 | params.suffix = suffix;
102 | return basename;
103 | });
104 | params.suffix = params.suffix != null ? params.suffix : '';
105 |
106 | if ((params.reqUrl = req.url) && (params.reqQuery = url.parse(params.reqUrl).query)) {
107 | query = querystring.parse(params.reqQuery);
108 | Object.keys(query).forEach(function(key) {
109 | if (typeof query[key] === 'string') {
110 | params['query_' + key] = query[key];
111 | } else { // it should be Array
112 | query[key].forEach(function(value, i) {
113 | params['query_' + key + '[' + i + ']'] = value + '';
114 | });
115 | }
116 | });
117 | }
118 |
119 | that._log('(%s) Requested: "%s"', params.reqPath, params.absPath);
120 |
121 | function inRoot(servePath) {
122 | return (platform === 'win32'
123 | ? servePath.toLowerCase().indexOf(that.root.toLowerCase()) : // Windows
124 | servePath.indexOf(that.root) // Others
125 | ) === 0 ? servePath : false;
126 | }
127 |
128 | function parseTemplate(template) {
129 | return template.replace(/<%\s*(.+?)\s*%>/g, function(s, key) {
130 | return params[key] != null ? params[key] : '';
131 | });
132 | }
133 |
134 | return that.options.alias.some(function(alias, iAlias) {
135 | var iMatch;
136 | if (!alias.match.some(function(match, i) {
137 | var key, value;
138 | if (typeof match === 'string') {
139 | value = match.replace(/^(?:(.*?)=)?(.*)$/, function(s, pKey, pValue) {
140 | key = pKey;
141 | return pValue;
142 | });
143 | if (params[key || 'reqPath'] === value) {
144 | iMatch = i;
145 | return true;
146 | }
147 | return false;
148 | }
149 | if (typeof match === 'object' && match instanceof RegExp && match.test(params.reqPath) ||
150 | typeof match === 'function' && match.call(that, params, req, res)) {
151 | iMatch = i;
152 | return true;
153 | }
154 | return false;
155 | })) {
156 | return false;
157 | }
158 | // matched
159 | return alias.serve.some(function(serve, iServe) {
160 | var absPath = // Not that.resolve() because it's not uri.
161 | typeof serve === 'string' ? path.resolve(that.root, parseTemplate(serve)) :
162 | typeof serve === 'function' ? path.resolve(that.root, serve.call(that, params, req, res)) :
163 | params.absPath;
164 | if (alias.force || fs.existsSync(absPath)) {
165 | servePath = absPath;
166 | allowOutside = alias.allowOutside;
167 | that._log('(%s) For Serve: "%s" alias[%d] match[%d] serve[%d]',
168 | params.reqPath, servePath, iAlias, iMatch, iServe);
169 | return true;
170 | }
171 | return false;
172 | });
173 | }) ? (allowOutside ? servePath : inRoot(servePath)) :
174 | inRoot(params.absPath);
175 | };
176 |
177 | exports.Server = Server;
178 | exports.mime = staticSuper.mime;
179 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # node-static-alias
2 |
3 | [](https://www.npmjs.com/package/node-static-alias) [](https://github.com/anseki/node-static-alias/issues) [](package.json) [](LICENSE)
4 |
5 | Serve static file which is not requested file. (e.g. `file.min.js` is requested, serve `file.js`)
6 | node-static-alias wraps (inherits) the useful module [node-static](https://github.com/cloudhead/node-static/), and this adds the [`alias`](#alias) option to that.
7 | This works like the [Alias](http://httpd.apache.org/docs/2.4/mod/mod_alias.html) mapping or the [mod_rewrite
8 | ](http://httpd.apache.org/docs/2.4/mod/mod_rewrite.html) of Apache. It looks like [DirectoryIndex](http://httpd.apache.org/docs/2.4/mod/mod_dir.html#directoryindex) too. And this can check the file exists or not.
9 |
10 | + Serve `file.js` instead of `file.min.js` which is not made yet, in the test phase.
11 | + Serve the outside files of the document-root which are shared by multiple web sites in one machine.
12 | + Serve the default page which is not `index.html` when *`/` is requested.
13 |
14 | ## Synopsis
15 |
16 | ```js
17 | var staticAlias = require('node-static-alias');
18 |
19 | // Document-Root: './public' directory
20 | var fileServer = new staticAlias.Server('./public', {
21 | alias: {
22 | match: '/path/to/file.min.js',
23 | serve: '/path/to/file.js'
24 | }
25 | });
26 |
27 | require('http').createServer(function(request, response) {
28 | request.addListener('end', function() {
29 | fileServer.serve(request, response);
30 | }).resume();
31 | }).listen(8080);
32 | ```
33 |
34 | ## Usage
35 |
36 | The [`alias`](#alias) option is added to the node-static via using `require('node-static-alias')` instead of `require('node-static')`. See [node-static](https://github.com/cloudhead/node-static/) to use it.
37 |
38 | ### `alias`
39 |
40 | The `alias` included in the constructor options is an Alias-Rule Object, or an array which includes multiple Alias-Rule Objects.
41 |
42 | ```js
43 | alias: {
44 | match: /file\.min\.(?:js|css)$/,
45 | serve: '/path/to/file.<% suffix %>'
46 | }
47 | ```
48 |
49 | Or
50 |
51 | ```js
52 | alias: [
53 | {
54 | match: '/path/to/file.min.js',
55 | serve: '/path/to/file.js'
56 | },
57 | {
58 | match: 'suffix=png',
59 | serve: '../outer/<% fileName %>',
60 | allowOutside: true
61 | }
62 | ]
63 | ```
64 |
65 | The Alias-Rule Object can have following properties.
66 |
67 | ### `match`
68 |
69 | **Type:** string, RegExp, function or Array
70 |
71 | Specify one of below or an Array which includes multiple things of those.
72 | If one or more things match, the [`serve`](#serve) is parsed. If anything doesn't match, it goes to next an Alias-Rule. If all Alias-Rules don't match, it tries to serve the requested file.
73 |
74 | + **string:**
75 | If the requested path is equal to this string, it's matched.
76 | Or, this can be `parameter=value` format (e.g. `suffix=png`). See [Parameters](#parameters). If the `value` is equal to the specified parameter, it's matched.
77 |
78 | ```js
79 | alias: [
80 | {
81 | match: '/path/to/file.min.js',
82 | serve: '/path/to/file.js'
83 | },
84 | // Image files are not made yet.
85 | {
86 | match: 'suffix=png',
87 | serve: '/path/to/dummy.png'
88 | }
89 | ]
90 | ```
91 |
92 | + **RegExp:**
93 | The RegExp which tests the requested path.
94 |
95 | ```js
96 | // These image files are not made yet.
97 | alias: {
98 | match: /\/(?:foo|bar)\.png$/,
99 | serve: '/path/to/dummy.png'
100 | }
101 | ```
102 |
103 | + **function:**
104 | The function which returns `true` or `false`.
105 | The Object which has parameters is passed to this function. See [Parameters](#parameters). Also, current `request` instance and `response` instance are passed.
106 | In the function, `this` refers to own instance.
107 |
108 | ```js
109 | // Kick direct access from outside web site.
110 | alias: {
111 | match: function(params, request, response) {
112 | console.log(request.url + ' was requested, in the path ' + this.root);
113 | return params.suffix === 'jpg' &&
114 | params.referer.indexOf('http://mysite.com/') !== 0;
115 | },
116 | serve: '/path/to/denial.jpg'
117 | }
118 | ```
119 |
120 | ### `serve`
121 |
122 | **Type:** string, function or Array
123 |
124 | Specify one of below or an Array which includes multiple things of those.
125 | By default, the first file which exists is chosen to try to serve. See [force](#force). If anything doesn't exist, it goes to next an Alias-Rule. If all files of Alias-Rules don't exist, it tries to serve the requested file.
126 |
127 | + **string:**
128 | The absolute path or relative path from the document-root of the file to serve.
129 | This can include parameters like `<% parameter %>`. See [Parameters](#parameters).
130 |
131 | ```js
132 | // directoryIndex isn't index.html
133 | alias: {
134 | match: /\/$/,
135 | serve: '<% absPath %>/default.html'
136 | }
137 | ```
138 |
139 | *NOTE:* If the first character of this string is `/` (it might be parameter), this string is absolute path. This `/` doesn't point the document-root. It is the root of the local filesystem. If you want the relative path from the document-root, don't specify leading `/`, or add `.` to left of leading `/`.
140 |
141 | + **function:**
142 | The function which returns the absolute path or relative path from the document-root of the file to serve.
143 | The Object which has parameters is passed to this function. See [Parameters](#parameters). Also, current `request` instance and `response` instance are passed.
144 | In the function, `this` refers to own instance.
145 |
146 | ```js
147 | // Minified files are not made yet.
148 | alias: {
149 | match: /\.min\.(?:js|css)$/,
150 | serve: function(params, request, response) {
151 | response.setHeader('X-serve-from', this.root);
152 | return params.absDir + '/' +
153 | params.basename.replace(/\.min$/, '.') + params.suffix;
154 | }
155 | }
156 | ```
157 |
158 | ```js
159 | // Compile unwatched SASS now.
160 | alias: {
161 | match: 'suffix=css',
162 | serve: function(params) {
163 | require('exec-sync')('sass ' +
164 | params.absDir + '/' + params.basename + '.scss:' + params.absPath);
165 | return params.absPath;
166 | }
167 | }
168 | ```
169 |
170 | ### `force`
171 |
172 | **Type:** boolean
173 |
174 | If `true` is specified, the first file in the [`serve`](#serve) is chosen to try to serve without checking it's existing or not. And if it doesn't exist, a 404 error occurs. Default is `false`.
175 | This is used to prevent another file from being chosen unintentionally.
176 |
177 | ### `allowOutside`
178 |
179 | If `true` is specified, serving the outside files of the document-root is allowed. Default is `false`.
180 |
181 | ```js
182 | // Shared files.
183 | alias: {
184 | match: /^\/common_lib/,
185 | serve: '/path/to/lib/<% fileName %>',
186 | allowOutside: true
187 | }
188 | ```
189 |
190 | *NOTE:* If you specify `true` in the public server, you should specify the absolute path to the [`serve`](#serve). Otherwise the user might access to the file that must be hidden from them.
191 |
192 | ## Parameters
193 |
194 | The string `parameter=value` can be specified to the [`match`](#match), and the string `<% parameter %>` can be specified to the [`serve`](#serve).
195 | And also, the Object which has parameters is passed to function which specified to the [`match`](#match) and the [`serve`](#serve).
196 | These parameters are below.
197 |
198 | + `reqUrl`
199 | The URL which is requested by the user. e.g. `/path/to/file.ext?key1=value1&key2=value2`
200 | + `reqPath`
201 | The path which is requested by the user. e.g. `/path/to/file.ext`
202 | This might be a directory. e.g. `/`
203 | + `reqDir`
204 | The path to a directory which is part of `reqPath`. e.g. `/path/to`
205 | + `absPath`
206 | The absolute path to a requested file. e.g. `/var/www/public/path/to/file.ext`
207 | + `absDir`
208 | The absolute path to a directory which is part of `absPath`. e.g. `/var/www/public/path/to`
209 | + `fileName`
210 | The file name of a requested file. e.g. `file.ext`
211 | This might be a directory name e.g. `to`
212 | If the document-root is requested, this is empty string.
213 | + `basename`
214 | The part of the file name except file-suffix. (`.` isn't included) e.g. `file`
215 | + `suffix`
216 | The part of the file name which is extracted file-suffix. (`.` isn't included) e.g. `ext`
217 | + `reqQuery`
218 | The URL query string which is part of `reqUrl`. e.g. `key1=value1&key2=value2`
219 | + Parsed query string
220 | Pairs of a key beginning with a `query_` and a value. e.g. `query_key1`: `value1`, `query_key2`: `value2` from `reqQuery` above
221 | An array is extracted and each key is given `[INDEX]`. e.g. `query_key[0]`: `value1`, `query_key[1]`: `value2` from `key=value1&key=value2`
222 | + Request Headers
223 | The HTTP Request Headers from the client. These are lower-cased. e.g. `referer`, `user-agent`, etc.
224 |
225 | ## Logging
226 |
227 | The `logger` included in constructor options is a Logger instance of the standard Logging Library (e.g. [log4js](https://github.com/nomiddlename/log4js-node)) which has `info` method or `log` method.
228 |
229 | ```js
230 | var log4js = require('log4js');
231 | var logger = log4js.getLogger('node-static-alias');
232 | logger.setLevel(log4js.levels.INFO);
233 |
234 | var fileServer = new staticAlias.Server('./public' {
235 | alias: { ... },
236 | logger: logger
237 | });
238 | ```
239 |
240 | You can specify a simple Object which has `info` method or `log` method (e.g. `console` or `util`).
241 | Most easy:
242 |
243 | ```js
244 | var fileServer = new staticAlias.Server('./public' {
245 | alias: { ... },
246 | logger: console
247 | //logger: require('util') // Add timestamp
248 | });
249 | ```
250 |
251 | Add project name: (But, you probably use your favorite library.)
252 |
253 | ```js
254 | var fileServer = new staticAlias.Server('./public' {
255 | alias: { ... },
256 | logger: {log: function() {
257 | var util = require('util');
258 | console.log('[node-static-alias] ' + util.format.apply(util, arguments));
259 | }}
260 | });
261 | ```
262 |
263 | Log message example:
264 |
265 | ```console
266 | (/) Requested: "/var/public"
267 | (/file.min.css) Requested: "/var/public/file.min.css"
268 | (/file.min.css) For Serve: "/var/public/file.css" alias[3] match[1] serve[0]
269 | (/file.min.js) Requested: "/var/public/file.min.js"
270 | (/file.min.js) For Serve: "/var/public/file.js" alias[2] match[0] serve[1]
271 | ```
272 |
273 | The `(path)` is the path which is requested by the user. The `[number]` means an index of an Array.
274 |
275 | ## Files list in the Directory
276 |
277 | This example generates a list of files and directories in requested directory when the user accessed the directory. This works like the [mod_autoindex](http://httpd.apache.org/docs/2.4/mod/mod_autoindex.html) of Apache.
278 |
279 | That looks like:
280 | 
281 |
282 | The [statsFilelist](https://www.npmjs.com/package/stats-filelist) is required.
283 |
284 | ```
285 | npm install stats-filelist
286 | ```
287 |
288 | Load that and some core modules.
289 |
290 | ```js
291 | var filelist = require('stats-filelist'),
292 | path = require('path'),
293 | fs = require('fs');
294 | ```
295 |
296 | Specify for `alias`:
297 |
298 | ```js
299 | alias: {
300 | match: function(params) {
301 | try {
302 | return fs.statSync(params.absPath).isDirectory();
303 | } catch (error) {
304 | return false; // Ignore "Not found" etc.
305 | }
306 | },
307 | serve: function(params) {
308 | var indexPath = path.join(params.absPath, '.index.html');
309 | fs.writeFileSync(indexPath,
310 | '' +
311 | filelist.getSync(params.absPath, /^(?!.*[/\\]\.index\.html$).+$/, false)
312 | .map(function(stat) {
313 | var relPath = stat.name + (stat.isDirectory() ? '/' : '');
314 | return '- ' + relPath + '
';
315 | }).join('') +
316 | '
');
317 | return indexPath;
318 | }
319 | }
320 | ```
321 |
--------------------------------------------------------------------------------