@flyewi/eleventy-plugin-redirects 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -37,7 +37,7 @@ By default this writes an `_redirects` file into your output directory after eve
37
37
  | `defaultStatus` | `301` | Status code used when an entry doesn't specify one. |
38
38
  | `netlify` | `true` | Write a Netlify `_redirects` file. |
39
39
  | `netlifyFile` | `"_redirects"` | Filename for the Netlify output, relative to the output directory. |
40
- | `apache` | `false` | Write an Apache `.htaccess` with `Redirect` directives. |
40
+ | `apache` | `false` | Write an Apache `.htaccess` with exact-match `RedirectMatch` directives. |
41
41
  | `apacheFile` | `".htaccess"` | Filename for the Apache output. |
42
42
  | `html` | `false` | Also write a static HTML fallback page at each `from` URL (meta-refresh + `rel=canonical`), for hosts (e.g. GitHub Pages) that can't act on `_redirects`/`.htaccess`. |
43
43
  | `htmlLang` | `"en"` | `lang` attribute of the HTML fallback pages. |
@@ -56,10 +56,16 @@ If your output directory already contains an `_redirects` file (e.g. copied thro
56
56
  ## Apache output
57
57
 
58
58
  ```
59
- Redirect 301 /old-path/ /new-path/
60
- Redirect 302 /legacy-page/ /new-page/
59
+ RedirectMatch 301 ^/old-path/$ /new-path/
60
+ RedirectMatch 302 ^/legacy-page/$ /new-page/
61
61
  ```
62
62
 
63
+ Each rule matches its path **exactly**, the same as in Netlify's `_redirects`: `/old-path/` redirects, `/old-path/sub/` does not. Regex characters in the path (e.g. the `.` in `/old.html`) are escaped, and paths containing spaces are quoted. The query string is passed on to the target unchanged.
64
+
65
+ > **Changed in 0.3.0:** earlier versions wrote `Redirect` directives, which Apache treats as a *prefix* match (`/old-path/` also redirected `/old-path/anything` to `/new-path/anything`). If you relied on that, add the deeper paths as separate entries.
66
+
67
+ Requires `mod_alias`, which is enabled on practically every Apache host, and `.htaccess` overrides (`AllowOverride FileInfo`) — on shared hosting this is usually the case.
68
+
63
69
  ## HTML fallback pages
64
70
 
65
71
  With `html: true`, each `from` path also gets a real HTML file at that URL (e.g. `/old-path/` → `old-path/index.html` in the output directory) containing:
@@ -74,6 +80,10 @@ The script redirects immediately and keeps the URL fragment (`/old-path/#section
74
80
 
75
81
  This is a static fallback for platforms without server-side redirect support — a real `_redirects`/`.htaccess` (or your host/CDN's redirect rules) is always the better option when available, since the HTML approach is a moment slower and depends on the browser executing the refresh.
76
82
 
83
+ ## Contributing
84
+
85
+ Issues and pull requests are welcome. For how releases are published, see [RELEASING.md](RELEASING.md).
86
+
77
87
  ## License
78
88
 
79
89
  MIT
package/lib/formats.js CHANGED
@@ -4,8 +4,28 @@ function toNetlify(list) {
4
4
  return list.map(({ from, to, status }) => `${from} ${to} ${status}`).join("\n") + "\n";
5
5
  }
6
6
 
7
+ function escapeRegex(str) {
8
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
9
+ }
10
+
11
+ // Apache splits directive arguments on whitespace; quote those that contain it.
12
+ function apacheArg(str) {
13
+ return /[\s"]/.test(str) ? `"${str.replace(/"/g, '\\"')}"` : str;
14
+ }
15
+
16
+ // RedirectMatch with an anchored, escaped pattern matches the path exactly,
17
+ // like Netlify's _redirects. Plain `Redirect` would be a prefix match
18
+ // (/old/ would also catch /old/anything), so the same config would behave
19
+ // differently depending on the host.
7
20
  function toApache(list) {
8
- return list.map(({ from, to, status }) => `Redirect ${status} ${from} ${to}`).join("\n") + "\n";
21
+ return (
22
+ list
23
+ .map(({ from, to, status }) => {
24
+ const pattern = apacheArg(`^${escapeRegex(from)}$`);
25
+ return `RedirectMatch ${status} ${pattern} ${apacheArg(to)}`;
26
+ })
27
+ .join("\n") + "\n"
28
+ );
9
29
  }
10
30
 
11
31
  function escapeAttr(str) {
package/lib/redirects.js CHANGED
@@ -52,7 +52,7 @@ module.exports = function redirectsPlugin(eleventyConfig, userOptions = {}) {
52
52
  // Preserve (and prepend ahead of) any existing .htaccess content, e.g.
53
53
  // hand-maintained directives (ErrorDocument, mod_deflate, mod_expires)
54
54
  // brought in via a static passthrough copy — this plugin only owns the
55
- // Redirect lines, not the whole file.
55
+ // RedirectMatch lines, not the whole file.
56
56
  const existing = readExisting(apachePath);
57
57
  fs.writeFileSync(apachePath, toApache(list) + existing);
58
58
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flyewi/eleventy-plugin-redirects",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "Eleventy plugin that generates Netlify _redirects, Apache .htaccess, and static HTML fallback pages from a single redirects config.",
5
5
  "main": "lib/redirects.js",
6
6
  "type": "commonjs",