Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PoC: Introduce FilePatternRouter #1805

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

usualoma
Copy link
Member

I've implemented another router!
It is debatable whether it is appropriate to add even more new routers, but I think this router has enough characteristics to merit discussion.

What features does this router have?

This is a router for file-based routing. Performance tuning was done by reducing the number of routing format patterns supported.

  • Less than 200 lines
  • Fast initialization
  • High performance

I haven't written a test yet, so it doesn't work properly, but it works on almost the same principle as RegExpRouter, so I think it will work if fixed bugs.

Benchmark

Nearly the same performance as RegExpRouter

% npm run bench:node

> bench:node
> tsx ./src/bench.mts

cpu: Apple M2 Pro
runtime: node v20.0.0 (arm64-darwin)

benchmark                                 time (avg)             (min … max)       p75       p99      p995
---------------------------------------------------------------------------- -----------------------------
• short static - GET /user
---------------------------------------------------------------------------- -----------------------------
Hono RegExpRouter                      58.91 ns/iter  (51.05 ns … 136.05 ns)  60.52 ns  107.4 ns 111.47 ns
Hono TrieRouter                       211.09 ns/iter (194.67 ns … 267.97 ns) 213.53 ns 252.62 ns 266.85 ns
Hono FilePatternRouter                  79.3 ns/iter   (69.47 ns … 502.8 ns)  80.72 ns 128.91 ns 132.31 ns
@medley/router                         88.29 ns/iter  (79.59 ns … 117.61 ns)  90.22 ns  101.7 ns 103.94 ns
find-my-way                            80.37 ns/iter     (71.42 ns … 106 ns)  83.82 ns  93.55 ns  95.64 ns
koa-tree-router                           76 ns/iter   (68.05 ns … 94.72 ns)  77.54 ns  87.96 ns  89.55 ns
trek-router                           100.55 ns/iter  (90.61 ns … 128.89 ns) 103.59 ns  116.5 ns 117.92 ns
express (WARNING: includes handling)    1.02 µs/iter   (979.55 ns … 1.07 µs)   1.03 µs   1.07 µs   1.07 µs
koa-router                              1.85 µs/iter     (1.81 µs … 1.89 µs)   1.87 µs   1.89 µs   1.89 µs
radix3                                 80.45 ns/iter   (72.74 ns … 98.29 ns)  81.12 ns  92.33 ns  95.23 ns

summary for short static - GET /user
  Hono RegExpRouter
   1.29x faster than koa-tree-router
   1.35x faster than Hono FilePatternRouter
   1.36x faster than find-my-way
   1.37x faster than radix3
   1.5x faster than @medley/router
   1.71x faster than trek-router
   3.58x faster than Hono TrieRouter
   17.31x faster than express (WARNING: includes handling)
   31.43x faster than koa-router

• static with same radix - GET /user/comments
---------------------------------------------------------------------------- -----------------------------
Hono RegExpRouter                      66.06 ns/iter   (59.44 ns … 82.79 ns)  67.34 ns  79.32 ns  79.89 ns
Hono TrieRouter                       233.42 ns/iter   (210.4 ns … 431.3 ns) 235.63 ns  260.6 ns 281.34 ns
Hono FilePatternRouter                 86.94 ns/iter  (78.55 ns … 141.28 ns)  88.44 ns  99.05 ns 107.49 ns
@medley/router                        135.26 ns/iter (124.11 ns … 153.46 ns) 138.38 ns 148.45 ns 150.34 ns
find-my-way                           147.39 ns/iter  (133.8 ns … 222.41 ns) 151.96 ns  163.5 ns 176.84 ns
koa-tree-router                       111.78 ns/iter  (99.56 ns … 191.88 ns) 116.47 ns 138.41 ns 139.72 ns
trek-router                           160.37 ns/iter (145.94 ns … 198.02 ns) 165.46 ns 191.18 ns 195.03 ns
express (WARNING: includes handling)    1.09 µs/iter      (1.04 µs … 1.2 µs)    1.1 µs    1.2 µs    1.2 µs
koa-router                              1.88 µs/iter     (1.84 µs … 1.97 µs)   1.89 µs   1.97 µs   1.97 µs
radix3                                 86.57 ns/iter  (77.52 ns … 130.18 ns)  88.57 ns 108.02 ns  114.7 ns

summary for static with same radix - GET /user/comments
  Hono RegExpRouter
   1.31x faster than radix3
   1.32x faster than Hono FilePatternRouter
   1.69x faster than koa-tree-router
   2.05x faster than @medley/router
   2.23x faster than find-my-way
   2.43x faster than trek-router
   3.53x faster than Hono TrieRouter
   16.48x faster than express (WARNING: includes handling)
   28.43x faster than koa-router

• dynamic route - GET /user/lookup/username/hey
---------------------------------------------------------------------------- -----------------------------
Hono RegExpRouter                     136.29 ns/iter (122.33 ns … 166.61 ns)  141.5 ns 154.23 ns 164.02 ns
Hono TrieRouter                       372.56 ns/iter (350.58 ns … 590.02 ns) 376.68 ns 433.76 ns 590.02 ns
Hono FilePatternRouter                  88.5 ns/iter   (80.05 ns … 113.7 ns)  90.63 ns 104.95 ns 110.15 ns
@medley/router                        188.55 ns/iter (170.17 ns … 247.84 ns)  192.1 ns 217.18 ns 218.54 ns
find-my-way                           223.37 ns/iter  (202.89 ns … 277.1 ns) 228.78 ns 262.39 ns 265.58 ns
koa-tree-router                       169.16 ns/iter (152.82 ns … 203.72 ns) 174.07 ns 193.65 ns 201.94 ns
trek-router                           268.98 ns/iter (249.23 ns … 317.05 ns) 274.48 ns 307.78 ns 317.05 ns
express (WARNING: includes handling)    1.73 µs/iter      (1.68 µs … 1.8 µs)   1.74 µs    1.8 µs    1.8 µs
koa-router                              1.88 µs/iter     (1.83 µs … 1.98 µs)   1.89 µs   1.98 µs   1.98 µs
radix3                                395.96 ns/iter (372.88 ns … 478.81 ns) 402.25 ns 434.68 ns 478.81 ns

summary for dynamic route - GET /user/lookup/username/hey
  Hono FilePatternRouter
   1.54x faster than Hono RegExpRouter
   1.91x faster than koa-tree-router
   2.13x faster than @medley/router
   2.52x faster than find-my-way
   3.04x faster than trek-router
   4.21x faster than Hono TrieRouter
   4.47x faster than radix3
   19.53x faster than express (WARNING: includes handling)
   21.24x faster than koa-router

• mixed static dynamic - GET /event/abcd1234/comments
---------------------------------------------------------------------------- -----------------------------
Hono RegExpRouter                     137.81 ns/iter    (120.05 ns … 282 ns) 140.41 ns 246.46 ns 268.75 ns
Hono TrieRouter                       410.34 ns/iter (377.88 ns … 765.28 ns) 411.47 ns 509.07 ns 765.28 ns
Hono FilePatternRouter                 86.65 ns/iter   (77.3 ns … 115.13 ns)   88.2 ns 102.59 ns 108.73 ns
@medley/router                        156.36 ns/iter  (144.2 ns … 390.76 ns) 159.08 ns  182.5 ns 291.98 ns
find-my-way                           200.26 ns/iter (179.33 ns … 581.04 ns) 203.52 ns 274.63 ns 392.51 ns
koa-tree-router                       141.91 ns/iter (128.65 ns … 168.74 ns) 147.58 ns 162.32 ns 166.07 ns
trek-router                           230.61 ns/iter (215.44 ns … 280.25 ns) 236.32 ns 264.18 ns 266.87 ns
express (WARNING: includes handling)    1.89 µs/iter     (1.81 µs … 2.16 µs)   1.91 µs   2.16 µs   2.16 µs
koa-router                              1.93 µs/iter     (1.85 µs … 2.44 µs)   1.93 µs   2.44 µs   2.44 µs
radix3                                376.95 ns/iter  (352.57 ns … 454.3 ns) 384.84 ns 402.63 ns  454.3 ns

summary for mixed static dynamic - GET /event/abcd1234/comments
  Hono FilePatternRouter
   1.59x faster than Hono RegExpRouter
   1.64x faster than koa-tree-router
   1.8x faster than @medley/router
   2.31x faster than find-my-way
   2.66x faster than trek-router
   4.35x faster than radix3
   4.74x faster than Hono TrieRouter
   21.86x faster than express (WARNING: includes handling)
   22.26x faster than koa-router

• post - POST /event/abcd1234/comment
---------------------------------------------------------------------------- -----------------------------
Hono RegExpRouter                     122.76 ns/iter (111.57 ns … 154.22 ns) 127.59 ns  145.9 ns 147.73 ns
Hono TrieRouter                       435.07 ns/iter (394.88 ns … 979.27 ns) 427.49 ns 777.25 ns 979.27 ns
Hono FilePatternRouter                138.52 ns/iter (124.78 ns … 260.35 ns)    142 ns  175.8 ns 194.97 ns
@medley/router                        149.17 ns/iter (139.13 ns … 343.57 ns) 152.33 ns  172.1 ns 186.98 ns
find-my-way                           203.02 ns/iter (182.47 ns … 747.03 ns) 202.47 ns 515.17 ns 565.67 ns
koa-tree-router                       135.33 ns/iter (118.64 ns … 718.98 ns) 137.77 ns 178.27 ns 427.55 ns
trek-router                            192.5 ns/iter  (178.58 ns … 226.7 ns) 198.45 ns 219.69 ns 225.13 ns
express (WARNING: includes handling)     1.9 µs/iter     (1.86 µs … 1.97 µs)   1.91 µs   1.97 µs   1.97 µs
koa-router                              1.91 µs/iter     (1.84 µs … 2.58 µs)    1.9 µs   2.58 µs   2.58 µs
radix3                                 375.8 ns/iter (353.62 ns … 458.61 ns)    381 ns 409.31 ns 458.61 ns

summary for post - POST /event/abcd1234/comment
  Hono RegExpRouter
   1.1x faster than koa-tree-router
   1.13x faster than Hono FilePatternRouter
   1.22x faster than @medley/router
   1.57x faster than trek-router
   1.65x faster than find-my-way
   3.06x faster than radix3
   3.54x faster than Hono TrieRouter
   15.45x faster than express (WARNING: includes handling)
   15.59x faster than koa-router

• long static - GET /very/deeply/nested/route/hello/there
---------------------------------------------------------------------------- -----------------------------
Hono RegExpRouter                      77.67 ns/iter    (66.17 ns … 1.05 µs)  75.78 ns  94.41 ns  97.32 ns
Hono TrieRouter                       334.03 ns/iter (305.36 ns … 922.28 ns) 338.85 ns 365.54 ns 922.28 ns
Hono FilePatternRouter                 96.46 ns/iter    (85.35 ns … 1.12 µs)  94.96 ns 124.45 ns 180.41 ns
@medley/router                        119.39 ns/iter      (105.41 ns … 1 µs) 116.87 ns 144.58 ns 685.12 ns
find-my-way                           197.86 ns/iter (183.28 ns … 230.28 ns) 203.15 ns 224.45 ns 229.51 ns
koa-tree-router                       115.76 ns/iter (104.94 ns … 951.02 ns)  117.1 ns 152.61 ns 180.44 ns
trek-router                           132.37 ns/iter (122.87 ns … 186.36 ns) 135.83 ns 153.37 ns 161.32 ns
express (WARNING: includes handling)    1.37 µs/iter     (1.31 µs … 1.57 µs)   1.38 µs   1.57 µs   1.57 µs
koa-router                              1.99 µs/iter     (1.82 µs … 2.93 µs)   2.01 µs   2.93 µs   2.93 µs
radix3                                 87.67 ns/iter  (78.33 ns … 929.75 ns)  87.28 ns 103.88 ns 112.37 ns

summary for long static - GET /very/deeply/nested/route/hello/there
  Hono RegExpRouter
   1.13x faster than radix3
   1.24x faster than Hono FilePatternRouter
   1.49x faster than koa-tree-router
   1.54x faster than @medley/router
   1.7x faster than trek-router
   2.55x faster than find-my-way
   4.3x faster than Hono TrieRouter
   17.67x faster than express (WARNING: includes handling)
   25.6x faster than koa-router

• wildcard - GET /static/index.html
---------------------------------------------------------------------------- -----------------------------
Hono RegExpRouter                     135.81 ns/iter (124.22 ns … 177.29 ns) 139.88 ns 165.33 ns 171.44 ns
Hono TrieRouter                       289.58 ns/iter   (259.91 ns … 1.35 µs) 281.46 ns 745.39 ns   1.35 µs
Hono FilePatternRouter                124.07 ns/iter (114.05 ns … 167.81 ns) 128.47 ns 142.99 ns 146.57 ns
@medley/router                        109.92 ns/iter  (97.46 ns … 255.35 ns) 111.77 ns 125.27 ns 126.26 ns
find-my-way                           170.38 ns/iter (157.22 ns … 216.25 ns) 175.78 ns 204.81 ns 209.27 ns
koa-tree-router                       143.54 ns/iter  (131.88 ns … 171.5 ns) 147.97 ns  163.4 ns 165.68 ns
trek-router                           171.31 ns/iter (158.74 ns … 208.93 ns) 176.14 ns 198.67 ns 208.67 ns
express (WARNING: includes handling)    2.11 µs/iter     (2.01 µs … 3.05 µs)   2.11 µs   3.05 µs   3.05 µs
koa-router                               1.9 µs/iter     (1.81 µs … 2.48 µs)   1.88 µs   2.48 µs   2.48 µs
radix3                                371.09 ns/iter (348.55 ns … 451.24 ns) 375.56 ns 438.87 ns 451.24 ns

summary for wildcard - GET /static/index.html
  @medley/router
   1.13x faster than Hono FilePatternRouter
   1.24x faster than Hono RegExpRouter
   1.31x faster than koa-tree-router
   1.55x faster than find-my-way
   1.56x faster than trek-router
   2.63x faster than Hono TrieRouter
   3.38x faster than radix3
   17.25x faster than koa-router
   19.15x faster than express (WARNING: includes handling)

• all together
---------------------------------------------------------------------------- -----------------------------
Hono RegExpRouter                     397.98 ns/iter   (369.44 ns … 1.08 µs)  398.2 ns 540.96 ns   1.08 µs
Hono TrieRouter                         2.02 µs/iter         (1.9 µs … 3 µs)      2 µs      3 µs      3 µs
Hono FilePatternRouter                 443.1 ns/iter   (399.37 ns … 1.71 µs) 435.84 ns 921.95 ns   1.71 µs
@medley/router                        665.74 ns/iter   (610.99 ns … 1.69 µs) 650.15 ns   1.69 µs   1.69 µs
find-my-way                             1.08 µs/iter   (994.02 ns … 2.33 µs)   1.05 µs   2.33 µs   2.33 µs
koa-tree-router                       611.28 ns/iter  (578.8 ns … 997.83 ns) 616.11 ns 997.83 ns 997.83 ns
trek-router                           976.31 ns/iter   (921.32 ns … 1.35 µs)  982.9 ns   1.35 µs   1.35 µs
express (WARNING: includes handling)   11.32 µs/iter     (9.92 µs … 7.32 ms)  10.83 µs   14.5 µs  15.67 µs
koa-router                             12.99 µs/iter    (11.63 µs … 2.17 ms)  12.63 µs  16.71 µs  24.21 µs
radix3                                  1.61 µs/iter     (1.47 µs … 2.96 µs)   1.55 µs   2.96 µs   2.96 µs

summary for all together
  Hono RegExpRouter
   1.11x faster than Hono FilePatternRouter
   1.54x faster than koa-tree-router
   1.67x faster than @medley/router
   2.45x faster than trek-router
   2.71x faster than find-my-way
   4.03x faster than radix3
   5.08x faster than Hono TrieRouter
   28.46x faster than express (WARNING: includes handling)
   32.63x faster than koa-router

Initialization performance is not as good as LinearRouter, but fast enough.

% npm run bench-includes-init:node

> bench-includes-init:node
> tsx ./src/bench-includes-init.mts

cpu: Apple M2 Pro
runtime: node v20.0.0 (arm64-darwin)

benchmark              time (avg)             (min … max)       p75       p99      p995
--------------------------------------------------------- -----------------------------
• GET /user
--------------------------------------------------------- -----------------------------
RegExpRouter        35.77 µs/iter   (26.21 µs … 15.11 ms)  31.42 µs  69.54 µs 375.42 µs
TrieRouter           5.76 µs/iter   (4.92 µs … 268.75 µs)   5.58 µs      7 µs   8.75 µs
LinearRouter       958.76 ns/iter (916.41 ns … 989.93 ns) 969.11 ns 989.93 ns 989.93 ns
FilePatternRouter    2.86 µs/iter     (2.81 µs … 2.91 µs)   2.87 µs   2.91 µs   2.91 µs
MedleyRouter         2.86 µs/iter     (2.81 µs … 2.93 µs)   2.87 µs   2.93 µs   2.93 µs
FindMyWay           89.77 µs/iter    (78.21 µs … 4.13 ms)  87.25 µs 160.25 µs 275.46 µs
KoaTreeRouter         2.1 µs/iter     (2.07 µs … 2.17 µs)   2.11 µs   2.17 µs   2.17 µs
TrekRouter           2.93 µs/iter     (2.87 µs … 3.07 µs)   2.94 µs   3.07 µs   3.07 µs

summary for GET /user
  LinearRouter
   2.19x faster than KoaTreeRouter
   2.98x faster than FilePatternRouter
   2.98x faster than MedleyRouter
   3.06x faster than TrekRouter
   6x faster than TrieRouter
   37.31x faster than RegExpRouter
   93.63x faster than FindMyWay

• GET /user/comments
--------------------------------------------------------- -----------------------------
RegExpRouter        36.52 µs/iter    (25.96 µs … 2.29 ms)  30.46 µs 230.38 µs 473.71 µs
TrieRouter           5.75 µs/iter      (5.68 µs … 5.9 µs)   5.76 µs    5.9 µs    5.9 µs
LinearRouter         1.05 µs/iter     (1.02 µs … 1.08 µs)   1.06 µs   1.08 µs   1.08 µs
FilePatternRouter    2.89 µs/iter     (2.82 µs … 2.95 µs)   2.92 µs   2.95 µs   2.95 µs
MedleyRouter         2.94 µs/iter     (2.89 µs … 3.06 µs)   2.96 µs   3.06 µs   3.06 µs
FindMyWay           93.93 µs/iter    (78.21 µs … 3.08 ms)  88.21 µs 280.21 µs 360.71 µs
KoaTreeRouter        2.16 µs/iter     (2.12 µs … 2.21 µs)   2.17 µs   2.21 µs   2.21 µs
TrekRouter              3 µs/iter      (2.93 µs … 3.1 µs)   3.04 µs    3.1 µs    3.1 µs

summary for GET /user/comments
  LinearRouter
   2.05x faster than KoaTreeRouter
   2.74x faster than FilePatternRouter
   2.8x faster than MedleyRouter
   2.86x faster than TrekRouter
   5.46x faster than TrieRouter
   34.73x faster than RegExpRouter
   89.32x faster than FindMyWay

• GET /user/lookup/username/hey
--------------------------------------------------------- -----------------------------
RegExpRouter        51.61 µs/iter    (26.17 µs … 9.83 ms)  31.13 µs 591.08 µs   1.15 ms
TrieRouter           5.98 µs/iter     (5.91 µs … 6.06 µs)   6.01 µs   6.06 µs   6.06 µs
LinearRouter         1.22 µs/iter     (1.18 µs … 1.28 µs)   1.23 µs   1.28 µs   1.28 µs
FilePatternRouter    2.96 µs/iter     (2.89 µs … 3.18 µs)   2.99 µs   3.18 µs   3.18 µs
MedleyRouter         3.02 µs/iter     (2.96 µs … 3.08 µs)   3.05 µs   3.08 µs   3.08 µs
FindMyWay           97.06 µs/iter    (80.46 µs … 3.59 ms)  89.46 µs 291.63 µs 372.83 µs
KoaTreeRouter        2.28 µs/iter     (2.18 µs … 2.67 µs)    2.3 µs   2.67 µs   2.67 µs
TrekRouter           3.11 µs/iter     (3.06 µs … 3.16 µs)   3.13 µs   3.16 µs   3.16 µs

summary for GET /user/lookup/username/hey
  LinearRouter
   1.87x faster than KoaTreeRouter
   2.43x faster than FilePatternRouter
   2.48x faster than MedleyRouter
   2.55x faster than TrekRouter
   4.9x faster than TrieRouter
   42.3x faster than RegExpRouter
   79.56x faster than FindMyWay

• GET /event/abcd1234/comments
--------------------------------------------------------- -----------------------------
RegExpRouter        51.52 µs/iter     (26.13 µs … 5.8 ms)  30.79 µs 542.96 µs   1.13 ms
TrieRouter           6.05 µs/iter     (5.94 µs … 6.39 µs)   6.11 µs   6.39 µs   6.39 µs
LinearRouter         1.24 µs/iter      (1.2 µs … 1.55 µs)   1.24 µs   1.55 µs   1.55 µs
FilePatternRouter    2.96 µs/iter     (2.88 µs … 3.48 µs)   2.97 µs   3.48 µs   3.48 µs
MedleyRouter         2.96 µs/iter     (2.93 µs … 3.02 µs)   2.98 µs   3.02 µs   3.02 µs
FindMyWay           92.96 µs/iter    (79.04 µs … 4.78 ms)  86.96 µs 255.75 µs 356.83 µs
KoaTreeRouter        2.19 µs/iter     (2.14 µs … 2.24 µs)    2.2 µs   2.24 µs   2.24 µs
TrekRouter           3.09 µs/iter     (3.04 µs … 3.18 µs)   3.11 µs   3.18 µs   3.18 µs

summary for GET /event/abcd1234/comments
  LinearRouter
   1.77x faster than KoaTreeRouter
   2.39x faster than FilePatternRouter
   2.4x faster than MedleyRouter
   2.5x faster than TrekRouter
   4.9x faster than TrieRouter
   41.66x faster than RegExpRouter
   75.17x faster than FindMyWay

• POST /event/abcd1234/comment
--------------------------------------------------------- -----------------------------
RegExpRouter        55.51 µs/iter    (26.08 µs … 9.95 ms)  31.13 µs 562.63 µs   1.13 ms
TrieRouter           6.08 µs/iter      (5.89 µs … 6.7 µs)   6.06 µs    6.7 µs    6.7 µs
LinearRouter       384.92 ns/iter  (360.12 ns … 456.6 ns)  390.7 ns 447.47 ns  456.6 ns
FilePatternRouter     3.1 µs/iter     (2.86 µs … 3.92 µs)   3.13 µs   3.92 µs   3.92 µs
MedleyRouter            3 µs/iter     (2.91 µs … 3.18 µs)   3.03 µs   3.18 µs   3.18 µs
FindMyWay           99.26 µs/iter    (80.08 µs … 9.37 ms)  87.71 µs 258.08 µs 368.63 µs
KoaTreeRouter        2.23 µs/iter     (2.13 µs … 2.98 µs)    2.2 µs   2.98 µs   2.98 µs
TrekRouter           3.08 µs/iter        (3 µs … 3.21 µs)   3.11 µs   3.21 µs   3.21 µs

summary for POST /event/abcd1234/comment
  LinearRouter
   5.8x faster than KoaTreeRouter
   7.81x faster than MedleyRouter
   7.99x faster than TrekRouter
   8.06x faster than FilePatternRouter
   15.8x faster than TrieRouter
   144.21x faster than RegExpRouter
   257.86x faster than FindMyWay

• GET /very/deeply/nested/route/hello/there
--------------------------------------------------------- -----------------------------
RegExpRouter        70.84 µs/iter   (26.33 µs … 12.93 ms)  31.08 µs 728.38 µs   1.45 ms
TrieRouter           5.96 µs/iter     (5.84 µs … 6.11 µs)   6.01 µs   6.11 µs   6.11 µs
LinearRouter         1.24 µs/iter     (1.16 µs … 1.71 µs)   1.25 µs   1.71 µs   1.71 µs
FilePatternRouter    3.03 µs/iter     (2.88 µs … 3.71 µs)   3.02 µs   3.71 µs   3.71 µs
MedleyRouter         3.05 µs/iter     (2.83 µs … 3.63 µs)   3.01 µs   3.63 µs   3.63 µs
FindMyWay          104.42 µs/iter   (79.21 µs … 12.81 ms)  86.88 µs 270.83 µs 451.88 µs
KoaTreeRouter        2.18 µs/iter     (2.11 µs … 2.39 µs)   2.18 µs   2.39 µs   2.39 µs
TrekRouter           2.99 µs/iter     (2.91 µs … 3.13 µs)   3.01 µs   3.13 µs   3.13 µs

summary for GET /very/deeply/nested/route/hello/there
  LinearRouter
   1.75x faster than KoaTreeRouter
   2.41x faster than TrekRouter
   2.44x faster than FilePatternRouter
   2.45x faster than MedleyRouter
   4.8x faster than TrieRouter
   57.09x faster than RegExpRouter
   84.14x faster than FindMyWay

• GET /static/index.html
--------------------------------------------------------- -----------------------------
RegExpRouter        79.11 µs/iter   (26.21 µs … 14.95 ms)     31 µs 721.13 µs   1.67 ms
TrieRouter           6.37 µs/iter        (5 µs … 14.3 ms)   5.71 µs   9.63 µs  14.92 µs
LinearRouter         1.06 µs/iter   (998.48 ns … 2.12 µs)   1.06 µs   2.12 µs   2.12 µs
FilePatternRouter    2.96 µs/iter     (2.81 µs … 3.74 µs)   2.99 µs   3.74 µs   3.74 µs
MedleyRouter         2.89 µs/iter     (2.77 µs … 3.14 µs)    2.9 µs   3.14 µs   3.14 µs
FindMyWay           102.3 µs/iter   (79.92 µs … 10.84 ms)  86.46 µs 204.29 µs 328.42 µs
KoaTreeRouter        2.19 µs/iter     (2.13 µs … 2.33 µs)   2.21 µs   2.33 µs   2.33 µs
TrekRouter           3.02 µs/iter     (2.93 µs … 3.13 µs)   3.04 µs   3.13 µs   3.13 µs

summary for GET /static/index.html
  LinearRouter
   2.06x faster than KoaTreeRouter
   2.72x faster than MedleyRouter
   2.79x faster than FilePatternRouter
   2.84x faster than TrekRouter
   6x faster than TrieRouter
   74.47x faster than RegExpRouter
   96.3x faster than FindMyWay

The bundle size of the application created with sonik on my environment was reduced as follows

71.27 kB -> 56.25 kB

Author should do the followings, if applicable

  • Add tests
  • Run tests
  • yarn denoify to generate files for Deno

@usualoma
Copy link
Member Author

@yusukebe How about a router like this?

@usualoma
Copy link
Member Author

Added basic tests by 8270f04

Now the performance of initialization is degrading.

% npm run bench-includes-init:node

....

  LinearRouter
   2.11x faster than KoaTreeRouter
   2.88x faster than MedleyRouter
   2.91x faster than TrekRouter
   5.28x faster than FilePatternRouter
   5.75x faster than TrieRouter
   75.12x faster than RegExpRouter
   89.9x faster than FindMyWay

@yusukebe
Copy link
Member

Hi @usualoma !

To ensure I understand correctly, I want to know the advantages of using FilePatternRouter for file-based routing. I think marking /foo/* as isMiddleware is a key point.

Btw, I'm currently working on changing the API of Sonik to make it simpler by using Hono's core features.

sonikjs/sonik#16

@usualoma
Copy link
Member Author

6e504c7 changes made it a little faster.

% npm run bench-includes-init:node

....

summary for GET /static/index.html
  LinearRouter
   2.13x faster than KoaTreeRouter
   2.79x faster than MedleyRouter
   2.89x faster than TrekRouter
   4.7x faster than FilePatternRouter
   5.62x faster than TrieRouter
   80.25x faster than RegExpRouter
   115.14x faster than FindMyWa

@usualoma
Copy link
Member Author

usualoma commented Dec 11, 2023

@yusukebe
Sorry, I will explain the specifications.

Supported Path Patterns

  • Static path
    • /path/to/static
  • Capture parameter
    • /posts/:id, /posts/:id/comments
  • Middleware
    • *, /*, /posts/*, posts/:id/*

The following are not supported

  • /wild/*/card
  • /post/:date{[0-9]+}/:title{[a-z]+}
  • /api/animals/:type?
  • /js/:filename{[a-z0-9/]+.js}

Other Restrictions

  • Maximum path length is 99 characters (but can be changed)

There are no other restrictions and FilePatternRouter can be used just like any other router.

At 41bbe94

  • Less than 200 lines -> About 200 lines
  • Fast initialization -> Not slow initialization
  • High performance
    • Even with the addition of tons of middleware, performance will not be degraded.

@yusukebe
Copy link
Member

Hi @usualoma,

Thank you for explaining the details. I fully understand now.

It's great to have a router specialized for file-based routing. As you mentioned, the patterns used in file-based routing are fewer than in normal Hono usage.

Currently, for my plan to release the file-based routing feature, I'm not sure if it will be Sonik, separate from this Hono repo, or another framework structure, but it will be released as v4. So, I think we should consider including this FilePatternRouter in v4. Until then, how about we keep this open?

@yusukebe yusukebe added the v4 label Dec 14, 2023
@usualoma
Copy link
Member Author

I agree 👍

I think we should consider including this FilePatternRouter in v4. Until then, how about we keep this open?

@usualoma
Copy link
Member Author

Sorry, I submitted once to #1850 by mistake.

Cons

I did not mention the cons of this router, so I will add them here.

The regex generated is large

The RegExpRouter compiled the regexes to be as small as possible, but the FilePatternRouter does not make that effort, so they become large for many routing registrations.

For example

  • app.get('/users/:id', handlerA)
  • app.get('/users/:id/posts', handlerB)
  • app.get('/users/:id/posts/:post_id', handlerC)

RegExpRouter: /users/([^/]+)(? :()|(? :/posts(? :()|/([^/]+)()))
FilePatternRouter: /users/([^/]+)/posts/([^/]+)()||/users/([^/]+)/posts()||/users/([^/]+)())

The current implementation is a PoC, so no effort has been made to make it smaller, but I think it could be made smaller by adding a few lines and allowing for a little overhead. Additional implementation would be necessary depending on the number of routings envisioned.

@yusukebe yusukebe removed the v4 label Jan 9, 2024
@rafaell-lycan
Copy link

rafaell-lycan commented Jan 29, 2024

@usualoma that's exciting!

I'm wondering how you can address a proper doc page with examples and tips on how to organize code. Would you be able to provide some examples on this PR?

I've used routing-controllers in the past which uses fancy Decorators, but they are not the same.

よくやった 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants