openresty-minifiers
Name
openresty-minifiers - A high-performance minifier library implemented by OpenResty Inc. that supports minification of HTML, CSS, and JavaScript files.
The library requires the private library replace-filter-plus module.
Table of Contents
Description
OpenResty Minifiers is composed of three distinct minifiers, each serving a unique purpose in the optimization of web content. These include:
- JS Minifier: This component is responsible for the minification of JavaScript files. It removes unnecessary characters like white spaces, new lines, and comments, thereby reducing the file size and improving the load time of your web pages.
- CSS Minifier: Similar to the JS Minifier, the CSS Minifier minifies CSS files. It optimizes the stylesheets by removing unnecessary characters and spaces, which results in faster page rendering.
- HTML Minifier: The HTML Minifier minifies HTML files. It eliminates redundant HTML tags, white spaces, and comments, leading to reduced bandwidth usage and faster page load times.
These minifiers are proprietary Nginx output filter modules that support
streaming processing. The time complexity is strictly O(n), where n is the
length of the response body data stream. The space complexity is strictly
O(1), meaning they use a constant amount of memory regardless of the input size.
Benchmark
They utilize a proprietary regular expression compiler based on our own DFA optimization algorithms.
In our benchmark, the JS-minifier module can achieve about 120+ MB/s
scanning speed on a single CPU core of Core i9-13900K. It supports streaming
processing using constant buffer sizes like 8KB.
Benchmark results can be viewed here: https://openresty.org/misc/re/bench/.
Synopsis
Load the replace-filter-plus module in the http block of
the OpenResty configuration file, and then load the openresty-minifiers
module in the init_by_lua_block block.
http {
...
load_module /usr/local/openresty/nginx/modules/ngx_http_replace_filter_module.so;
init_by_lua_block { require "resty.replace" }
...
}
You can load min-js.so, min-html.so, min-css.so according to your needs, which can minimize js, html, css files respectively:
js-minifier
http {
replace_filter_preload /usr/local/openresty-minifiers/lib/min-js.so
/usr/local/openresty-minifiers/tpls/min-js.tpl;
server {
...
location ~ \.js$ {
replace_filter_types application/javascript;
replace_filter_max_buffered_size 8k;
access_by_lua_block {
local ok, err = require "resty.replace".pick("min-js")
if not ok then
error("failed to pick replace prog: " .. err)
end
}
}
}
}
html-minifier
http {
replace_filter_preload /usr/local/openresty-minifiers/lib/min-html.so
/usr/local/openresty-minifiers/tpls/min-html.tpl;
server {
...
location ~ \.html$ {
replace_filter_types text/html;
replace_filter_max_buffered_size 8k;
access_by_lua_block {
local ok, err = require "resty.replace".pick("min-html")
if not ok then
error("failed to pick replace prog: " .. err)
end
}
}
}
}
css-minifier
http {
replace_filter_preload /usr/local/openresty-minifiers/lib/min-css.so
/usr/local/openresty-minifiers/tpls/min-css.tpl;
server {
...
location ~ \.css$ {
replace_filter_types text/css;
replace_filter_max_buffered_size 8k;
access_by_lua_block {
local ok, err = require "resty.replace".pick("min-css")
if not ok then
error("failed to pick replace prog: " .. err)
end
}
}
}
}
Installation
Configure the software repository
First we need to configure the repository for the binary installer, follow the
command below. (The CLIENT_TOKEN in the command needs to be replaced with
a valid Token from the subscription email)
curl -o get-xray-priv-lib-repo.sh https://pkg2.openresty.com/scripts/get-xray-priv-lib-repo.sh
sudo bash get-xray-priv-lib-repo.sh -l openresty-minifiers -t CLIENT_TOKEN
Installing packages
Note: The following installation instructions are for OpenResty 1.21.4.x.
For operating systems using the yum package manager, run the following command to install the private library.
sudo yum install -y openresty-minifiers replace-filter-plus-nginx-module-1.21.4
For operating systems using the dnf package manager, execute the following command to install the private libraries.
sudo dnf install -y openresty-minifiers replace-filter-plus-nginx-module-1.21.4
For operating systems using the apt package manager, execute the following command to install the private libraries.
sudo apt-get install -y openresty-minifiers replace-filter-plus-nginx-module-1.21.4
Directives
The following directives are available in the replace-filter-plus module, which is the dependency of the openresty-minifiers module.
replace_filter_preload
syntax: replace_filter_preload <so_path> <templatefile>;
default: no
context: http
Load the or-regex pre-generated .so file and template file, and insert into the hash table during the init phase. Extract the filename of so_path as key, without the file suffix.
The example as follows:
http {
replace_filter_preload /usr/local/openresty-minifiers/lib/min-html.so /usr/local/openresty-minifiers/tpls/min-html.tpl;
replace_filter_preload /usr/local/openresty-minifiers/lib/min-css.so /usr/local/openresty-minifiers/tpls/min-css.tpl;
replace_filter_preload /usr/local/openresty-minifiers/lib/min-js.so /usr/local/openresty-minifiers/tpls/min-js.tpl;
}
The filename of /usr/local/openresty-minifiers/lib/min-html.so is extracted to min-html as hashkey.
The template file format is as follows:
"$&" g
"$&" g
"" g
The quoting rules should follow the nginx config file’s string syntax or something similar.
replace_filter_types
syntax: replace_filter_types <mime-type> …
default: replace_filter_types text/html
context: http, server, location, location if
phase: output body filter
Specify one or more MIME types (in the Content-Type response header) to be processed.
By default, only text/html typed responses are processed.
Programs explicitly selected through the Lua API bypass this check. The caller must select a program appropriate for the response type.
replace_filter_max_buffered_size
syntax: replace_filter_max_buffered_size <size>
default: replace_filter_max_buffered_size 8k
context: http, server, location, location if
phase: output body filter
Limits the total size of the data buffered by the module at runtime. Default to 8k.
replace_filter_last_modified
syntax: replace_filter_last_modifiled keep | clear
default: replace_filter_last_modified clear
context: http, server, location, location if
phase: output body filter
Controls how to deal with the existing Last-Modified response header.
By default, this module will clear the Last-Modified response header if there is any. You can specify
replace_filter_last_modified keep;
to always keep the original Last-Modified response header.
replace_filter_skip
syntax: replace_filter_skip value
default: no
context: http, server, location, location if
phase: output header filter
Controls whether to skip replacement for the current response. An empty string or "0" allows replacement; any other value skips it. Values may contain NGINX variables.
API for Lua
pick() selects a preloaded program during the access phase; the module’s subsequent header filter decides whether to enable it. enable() checks the response and enables the program immediately in header_filter_by_lua_block, when the upstream response headers are available. Use it when selecting a minifier based on Content-Type.
| Property | pick(name) | enable(name) |
|---|---|---|
| Call phase | access_by_lua_block | header_filter_by_lua_block |
| Use case | The program is known during request processing | Selection depends on response headers |
| Response checks and header adjustments | Performed later by the module’s header filter | Performed during the call |
| Success result | true: selected, but the response may still be skipped | true: enabled |
| Skip or failure result | nil, err: selection failed | false, reason: skipped; nil, err: failed |
Response eligibility
- Programs selected from Lua bypass
replace_filter_types. The caller must choose a program appropriate for the response MIME type; this directive does not protect JSON, images, or other unsuitable responses from a Lua-selected program. - Responses with a nonempty
Content-Encoding(such asgzip),Content-Length: 0, or a truereplace_filter_skipvalue are skipped. Their bodies and relevant headers remain unchanged. - Enabling a program clears
Content-LengthandAccept-Ranges. It also clearsLast-Modifiedby default, unlessreplace_filter_last_modified keepis configured. - Only main requests are processed. Subrequest bodies and headers pass through unchanged, including for subrequests with
replace_filterconfigured. A body captured withngx.location.capture()can still be replaced once when emitted by an enabled main request. - Only one program can be selected per request. Repeated
enable(A)calls returntrueonce A is enabled. Callingenable(A)afterpick(A)is supported; if A is still disabled, response checks run before activation. Selecting a different program returnsnil, "current request already set prog".
Use pick() when the program is known during the access phase. To select a program from response headers, call enable() in header_filter_by_lua_block; it checks the response and adjusts the response headers.
find_prog_id(name)
Looks up the program ID using the filename loaded by replace_filter_preload, without the .so extension. For example, min-html.so is named min-html. name must be a string. Returns -1 when no program is found.
set_prog_by_id(r, prog_id)
Selects a program during the access phase. r is the request pointer obtained from require("resty.core.base").get_request(), and prog_id is an ID returned by find_prog_id().
Returns nil on success, or an error string on failure. Subrequests return "subrequests are not supported" without selecting a program. Successful selection does not guarantee that the response will be modified; the subsequent response checks must still pass.
pick(name)
A convenience interface that looks up the program ID and calls set_prog_by_id() for the current request. Only successful lookups are cached.
access_by_lua_block {
local ok, err = require("resty.replace").pick("min-js")
if not ok then
ngx.log(ngx.ERR, "failed to pick minifier: ", err)
end
}
Returns true on success, or nil, err on failure; it does not return false. Unknown names return nil, "replace program not found: <name>". Selecting a known program in a subrequest returns nil, "subrequests are not supported".
enable(name)
Call only in header_filter_by_lua_block. It checks the current response, enables the program, and adjusts the response headers on success. The caller does not need to clear these headers manually.
| Return value | Meaning |
|---|---|
true | The requested program is enabled, including when it was already enabled. |
false, "empty response body" | Content-Length is 0. |
false, "response body is content-encoded" | Content-Encoding is nonempty. |
false, "replace_filter_skip is true" | replace_filter_skip evaluates to true. |
false, "subrequests are not supported" | The current request is a subrequest. |
nil, err | Unknown program, a conflicting program, invalid call phase, or another error. |
A false result selects no new program and changes no response headers; a program previously selected with pick() remains selected but disabled. Unknown names return replace program not found: <name>; an invalid call phase returns API disabled in the current context. Invalid argument types raise a Lua error.
Once the requested program is enabled, repeated calls return true without rechecking the response or adjusting headers again. The header-filter phase and unsent-header requirements still apply.
If no program was selected earlier, native replace_filter rules take precedence over enable() when they apply to the response, including inherited rules. The call returns nil, "current request already set prog" regardless of module order. If the response does not match replace_filter_types, the native rules do not prevent Lua activation. Skipped, content-encoded, and empty responses still return false, reason.
enable_prog_by_id(r, prog_id)
The ID-based form of enable(). r and prog_id have the same meanings as in set_prog_by_id(). The call phase, response checks, and true / false, reason / nil, err return convention match enable(). An invalid ID returns nil, "invalid prog id".
Selecting a minifier from response headers
This example requires a version that supports enable(), assumes the filter module is loaded, and assumes an upstream named backend is configured. It accepts MIME parameters such as text/css; charset=utf-8, skips unlisted types, and uses enable() to select a minifier from the final response headers. The upstream request clears Accept-Encoding; if the upstream still returns an encoded response, the module skips it.
http {
replace_filter_preload /usr/local/openresty-minifiers/lib/min-html.so
/usr/local/openresty-minifiers/tpls/min-html.tpl;
replace_filter_preload /usr/local/openresty-minifiers/lib/min-css.so
/usr/local/openresty-minifiers/tpls/min-css.tpl;
replace_filter_preload /usr/local/openresty-minifiers/lib/min-js.so
/usr/local/openresty-minifiers/tpls/min-js.tpl;
server {
location / {
proxy_set_header Accept-Encoding "";
proxy_pass http://backend;
header_filter_by_lua_block {
local content_type = ngx.header.content_type or ""
local match = ngx.re.match(content_type, [[^\s*([^;\s]+)]], "jo")
if not match then
return
end
local mime = string.lower(match[1])
local name
if mime == "text/html" then
name = "min-html"
elseif mime == "text/css" then
name = "min-css"
elseif mime == "text/javascript"
or mime == "application/javascript"
then
name = "min-js"
else
return
end
local ok, err = require("resty.replace").enable(name)
if ok == nil then
ngx.log(ngx.ERR, "failed to enable minifier: ", err)
end
}
}
}
}
Copyright & Licese
Copyright (C) by OpenResty Inc. All rights reserved.
This software is proprietary and must not be redistributed or shared at all.