1
0
mirror of synced 2026-02-07 03:00:10 -05:00

Compare commits

...

40 Commits

Author SHA1 Message Date
Brandon Bayer
4068b4493e upgrade monorepo react to v18 alpha 2021-07-05 16:37:39 -04:00
Brandon Bayer
0448535ef0 Add test for Page.redirectAuthenticatedTo (#2531)
(meta)
2021-07-05 16:21:00 -04:00
Brandon Bayer
0df6aef3a3 fix broken api routes in canary release (#2545)
(patch)
2021-07-05 12:50:56 -04:00
Brandon Bayer
5ba2989592 fix cli npm build
(ignore)
2021-07-05 12:45:24 -04:00
Blitz.js Bot
9240d86ed6 (meta) added @esemeniuc as contributor 2021-07-05 12:09:51 -04:00
Eric Semeniuc
27e0dacdaf Route manifest replace nbsp with normal space (#2482)
Co-authored-by: Brandon Bayer <b@bayer.ws> (patch)
2021-07-05 12:09:46 -04:00
Brandon Bayer
8dc1cd3ca8 Fix CSRF error when using session.$setPublicData (#2541)
(patch)
2021-07-05 11:03:16 -04:00
Brandon Bayer
413bc01676 bump recipe/example versions (ignore) 2021-06-24 21:11:02 -06:00
Brandon Bayer
7c025e9bd7 v0.38.3-canary.1 2021-06-24 21:09:13 -06:00
Brandon Bayer
24e51c7ae5 Next.js Fork Migration: Move blitz.config.(js|ts) support into nextjs core (patch) (#2532) 2021-06-24 23:06:55 -04:00
Brandon Bayer
b2f84f1224 bump recipe/example versions (ignore) 2021-06-24 11:40:33 -06:00
Brandon Bayer
8df18f24ad v0.38.3-canary.0 2021-06-24 11:39:25 -06:00
Brandon Bayer
d480d84e46 Move multiple pages folders support plus pages+api sibling into nextjs core (#2502)
(patch)
2021-06-24 13:37:34 -04:00
Brandon Bayer
f0a9fbeb14 bump recipe/example versions (ignore) 2021-06-24 10:00:19 -06:00
Brandon Bayer
fe8179b595 v0.38.2 2021-06-24 09:59:06 -06:00
Brandon Bayer
6eaed7a3b2 tweak internal tsconfig
(ignore)
2021-06-24 09:57:59 -06:00
Brandon Bayer
69e97017b1 Fix built in errors like RedirectError and AuthenticationError to not log as "uncaught" in browser console (#2522)
(patch)
2021-06-24 11:45:58 -04:00
Brandon Bayer
1aa2d79ef4 git subrepo push --force nextjs
subrepo:
  subdir:   "nextjs"
  merged:   "4be32b7a5"
upstream:
  origin:   "git@github.com:blitz-js/next.js.git"
  branch:   "canary"
  commit:   "4be32b7a5"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"
2021-06-23 18:54:24 -06:00
Brandon Bayer
194a3720ce build script (ignore) 2021-06-23 18:52:11 -06:00
Brandon Bayer
e21b22d672 git subrepo push nextjs
subrepo:
  subdir:   "nextjs"
  merged:   "018261ad9"
upstream:
  origin:   "git@github.com:blitz-js/next.js.git"
  branch:   "canary"
  commit:   "018261ad9"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"
2021-06-23 18:48:33 -06:00
Brandon Bayer
b634fe9587 Upgrade to Next.js 11.0.1 (#2526)
(patch)
2021-06-23 20:34:58 -04:00
t.kuriyama
9b35fcd018 Fix blitz db seed to print stack traces for any errors (#2528)
(patch)
2021-06-23 19:49:36 -04:00
Simon Knott
d16ed02a50 Fix prefetched dehydrated state to support Dates, Maps, etc (patch) (#2512)
Co-authored-by: Brandon Bayer <b@bayer.ws>
2021-06-21 13:23:26 -04:00
Blitz.js Bot
bdec5cffbf (meta) updated @Cristy94 contributions 2021-06-21 13:17:37 -04:00
Buleandra Cristian
be430e093d Update userTrack logo (sponsor) (#2517)
(meta)
2021-06-21 13:17:32 -04:00
Brandon Bayer
3deb0045f4 bump recipe/example versions (ignore) 2021-06-19 17:28:04 -06:00
Brandon Bayer
c19e71624e v0.38.1 2021-06-19 17:25:42 -06:00
Blitz.js Bot
b6fcba1c01 (meta) added @benjakugler96 as contributor 2021-06-19 18:11:54 -04:00
Benja Kugler
dbdb6a4199 Fix browser error when using prisma.$use() (#2514)
Co-authored-by: benjamin.kugler <benjamin.kugler@elliemae.com> (patch)
2021-06-19 18:11:49 -04:00
Brandon Bayer
c151b3571e fix lint warning, unused path in generated api routes (patch) (#2513) 2021-06-19 15:20:55 -04:00
Blitz.js Bot
6198025ce5 (meta) added @prisis as contributor 2021-06-19 14:19:34 -04:00
Daniel Bannert
c9dba04f56 Fix so that npm scripts don't run on blitz install recipes (#2498)
Co-authored-by: danielb <daniel.bannert@limango.de> (patch)
2021-06-19 14:19:29 -04:00
Blitz.js Bot
a2c6c9ce23 (meta) updated @ntgussoni contributions 2021-06-19 14:01:48 -04:00
Nicolas Torres
b09c188113 Add support for custom messages and icons in recipes (#2510)
Adds ability to customize the success message icon in recipes (patch)

Co-authored-by: Nicolas <ntorres.dev@gmail.com>
2021-06-19 14:01:22 -04:00
Dustin Bachrach
cdd71af1cf Fix blitz generate to regenerate the Routes manifest (#2504)
(patch)
2021-06-19 13:58:55 -04:00
Brandon Bayer
54647d0054 fix validateZodSchema() to pass if schema undefined (#2511)
(patch)
2021-06-19 13:57:47 -04:00
Blitz.js Bot
1e39604ae1 (meta) added @igeligel as contributor 2021-06-18 12:22:31 -04:00
Dustin Bachrach
2f890b72ca Fix blitz generate /new page does not use Routes (#2501)
(patch)
2021-06-18 12:03:42 -04:00
Brandon Bayer
2a9125def5 bump recipe/example versions (ignore) 2021-06-17 09:32:09 -04:00
Brandon Bayer
2111ca6fae v0.38.0 2021-06-17 09:30:01 -04:00
306 changed files with 6479 additions and 2129 deletions

View File

@@ -357,7 +357,8 @@
"contributions": [
"test",
"code",
"review"
"review",
"doc"
]
},
{
@@ -2411,7 +2412,8 @@
"avatar_url": "https://avatars.githubusercontent.com/u/1384885?v=4",
"profile": "www.usertrack.net",
"contributions": [
"doc"
"doc",
"code"
]
},
{
@@ -2831,6 +2833,43 @@
"contributions": [
"doc"
]
},
{
"login": "igeligel",
"name": "Kevin Peters",
"avatar_url": "https://avatars.githubusercontent.com/u/12736734?v=4",
"profile": "https://www.kevinpeters.net/about/",
"contributions": [
"doc"
]
},
{
"login": "prisis",
"name": "Daniel Bannert",
"avatar_url": "https://avatars.githubusercontent.com/u/2716058?v=4",
"profile": "http://anolilab.de",
"contributions": [
"code"
]
},
{
"login": "benjakugler96",
"name": "Benja Kugler",
"avatar_url": "https://avatars.githubusercontent.com/u/53273645?v=4",
"profile": "https://benjakugler96.github.io/",
"contributions": [
"code"
]
},
{
"login": "esemeniuc",
"name": "Eric Semeniuc",
"avatar_url": "https://avatars.githubusercontent.com/u/3838856?v=4",
"profile": "https://semeniuc.ml/",
"contributions": [
"test",
"code"
]
}
],
"contributorsPerLine": 7,

View File

@@ -30,9 +30,9 @@ jobs:
path: |
${{ steps.yarn-cache-dir-path.outputs.dir }}
**/node_modules
key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v12-${{ hashFiles('yarn.lock') }}
key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v13-${{ hashFiles('yarn.lock') }}
restore-keys: |
${{ runner.os }}-${{ runner.node_version}}-yarn-v12-
${{ runner.os }}-${{ runner.node_version}}-yarn-v13-
- name: Install dependencies
run: yarn install --frozen-lockfile --silent
env:
@@ -76,9 +76,9 @@ jobs:
path: |
${{ steps.yarn-cache-dir-path.outputs.dir }}
**/node_modules
key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v12-${{ hashFiles('yarn.lock') }}
key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v13-${{ hashFiles('yarn.lock') }}
restore-keys: |
${{ runner.os }}-${{ runner.node_version}}-yarn-v12-
${{ runner.os }}-${{ runner.node_version}}-yarn-v13-
- run: yarn install --frozen-lockfile --check-files
- name: Build Packages
run: yarn build
@@ -144,9 +144,9 @@ jobs:
path: |
${{ steps.yarn-cache-dir-path.outputs.dir }}
**/node_modules
key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v12-${{ hashFiles('yarn.lock') }}
key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v13-${{ hashFiles('yarn.lock') }}
restore-keys: |
${{ runner.os }}-${{ runner.node_version}}-yarn-v12-
${{ runner.os }}-${{ runner.node_version}}-yarn-v13-
- run: yarn install --frozen-lockfile --check-files
# - run: yarn cpy node_modules/.blitz packages/core/node_modules/.blitz
# if: matrix.os == 'windows-latest'

1
.gitignore vendored
View File

@@ -30,3 +30,4 @@ examples/auth2
db.sqlite-journal
test/integration/**/db.json
test/**/*/out
.blitz**

View File

@@ -13,11 +13,14 @@
1. `git pull`
2. `git fetch --all`
3. `git merge v10.2.0` (change the version to be the version you are updating to)
4. Resolve all merge conflicts and complete merge
- Run `rm -rf examples && git add examples`
5. `git push`
4. Run `rm -rf examples && git add examples`
5. To resolve conflict with their version for a path, like docs, run this:
- `git checkout --theirs docs && git add docs`
6. Resolve all merge conflicts and complete merge
7. Run `yarn` and make sure all builds complete
8. Run `yarn lint` and fix any issues
9. `git push`
4. Run `yarn pull next-nextjs`
- If it fails, run `git subrepo clean nextjs` and try again
5. Run `yarn`
6. Run `yarn manypkg check` and optionally `yarn manypkg fix` to fix any issues
7. Under `nextjs/`, run `./check-pre-compiled.sh` and commit the changes
@@ -26,7 +29,7 @@
10. Run `yarn build` - fix any issues
11. Run `yarn test:nextjs-size` and update tests if there are any failures
12. Open PR and fix any failing tests
13. Any new features?
14. Any doc updates?
13. Update any references to nextjs in new code including imports like `next/image`, etc.
14. Any doc updates needed?
15. Merge PR
16. `yarn push-nextjs`

View File

@@ -6,7 +6,7 @@
<img alt="" src="https://img.shields.io/badge/Join%20our%20community-6700EB.svg?style=for-the-badge&labelColor=000000&logoWidth=20&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAQ9SURBVHgB7d3dVdtAEIbhcSpICUoH0IEogQqSVBBSAU4FSSpIOoAORAfQgSghHXzZ1U/YcMD4R9rZmf2ec3y448LyiNf27iLiGIAmPLrweC9Un3DhrzG6EarLNP09nlwJ1SOZ/lQr5N80/S/p2QMVCBf5N17XCfm1Y/rBHqjAG9PPHvBsz+mf9WAP+HLA9M/YA14cOP2payH7jpj+VCtk1wnTP+vj7xCy6cTpn7EHLMLp059iD1iD8eveJbVCNsSLheX1YA/YgOWnf8YeKB3Wmf7Ud6Fy4f/FHmtpxbl3YlC4MJ/Cj0bWdwPnPbARg+L0S54XQHS32WwuxClzd4CM0z9rPfeAuTtA5ulPXYQ7wZ04Y+oOoDD9KZc9YOoOoDj9s4dwFzgXR6w1wIPoOvPWA9buAHEJ173o3gWiy3AnuBUHLEbgmYwvAk1/wuM8vAgexThzbwPDkx7/DHwVXfFOxP2GmsKd4Ab6zPeAyU8CI7AHFmH2BRCBPXAyk18GzUrqAXCTiR4ssyj0VFw/oCU8+e+RZ33AWz6KMaYbIIWxB+JSLs1bsbkeMN0AqakHvoku9oA2sAfqBvbAQdw0QArsgb25aYBUQT3QgT2gB+yBuqGcHij2UCqXDZACe2Anlw2QYg/QAOyBuoE98CL3DZDCuK4/rh/Q7oGL6U+TOvcNkJoijN8X1C48+T+g75eQDrAH/qmqAVJgDwyqaoAUe4AGYA/UDZX3QLUNkEIZPRCd5+6BahsgVUgPROwBTSijB7jpVAvGHriHvmw9wAZ4BpX1ABvgmakHtPcbRuwBTWAPULgAV9D/jKDY9YRvwvgEaurD44uQHvAol7qBW7WKluVtIHiUS7GyvA0s6CiXDnxrpQfsgbqBS7GKk/2jYHCrVlGyfxTMrVo0ALdq1Q3sgSKofh0M9oA61a+D2QM0AHugbmAPqClmSRjK2apVVQ8UsySsoK1aHdgDesCtWnUDeyCrIpeFg1u3sylyWTi3btMA7IG6gT2wuuK3hoE9sKrit4YVslWLPaAN7IG6ocKt2zmY2h4O9sDiTG0PZw/QANy6XTewBxZj9ogYVHy025LMHhEz9cBn0We6B0yfERReBLfhx0/R1YQHPx/QBPbA0VwcEwf2wNFcHBPHHjiem3MC2QPHcXdSaJjA+KfgTPQ8hhfjBzHC40mhlzJ+Xq9lK4a4PCs43AVaGTed5mZq+iOXZwWHi3AnOj2wFWNcnxYe7gTxLtBKHuamP/J+Wnh8a5irB7ZC5Yk9gPX1QuXC+usHWqGyhYvUYR0a7zboUOFCNVhnk0krZAOW7wFOvzXhom2xnEbIHizTA1wEYhWW6YFGyC6c1gOcfg9wfA80Qj7g8B7g9HuCww+haIR8wf49wOn3Cvv9k8tGyC/s7gFOv3fY3QONkH+v9MBWqB7PeqDn9FcIT//kcitUn6kHOu/T/xfWzlQy3dEHhwAAAABJRU5ErkJggg==">
</a>
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
<a aria-label="All Contributors" href="#contributors-"><img alt="" src="https://img.shields.io/badge/all_contributors-300-17BB8A.svg?style=for-the-badge&labelColor=000000"></a>
<a aria-label="All Contributors" href="#contributors-"><img alt="" src="https://img.shields.io/badge/all_contributors-304-17BB8A.svg?style=for-the-badge&labelColor=000000"></a>
<!-- ALL-CONTRIBUTORS-BADGE:END -->
<a aria-label="License" href="https://github.com/blitz-js/blitz/blob/canary/LICENSE">
<img alt="" src="https://img.shields.io/npm/l/blitz.svg?style=for-the-badge&labelColor=000000&color=blue">
@@ -288,7 +288,7 @@ Thanks to these wonderful people ([emoji key](https://allcontributors.org/docs/e
<td align="center"><a href="https://mikeattara.com"><img src="https://avatars1.githubusercontent.com/u/31483629?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mike Perry Y Attara</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=mikeattara" title="Documentation">📖</a></td>
<td align="center"><a href="https://devanthe.dev"><img src="https://avatars0.githubusercontent.com/u/354652?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Devan</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=DevanB" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/jclancy93"><img src="https://avatars2.githubusercontent.com/u/7850202?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jack Clancy</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=jclancy93" title="Code">💻</a> <a href="#maintenance-jclancy93" title="Maintenance">🚧</a></td>
<td align="center"><a href="https://github.com/ntgussoni"><img src="https://avatars0.githubusercontent.com/u/10161067?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Nicolas Torres</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=ntgussoni" title="Tests">⚠️</a> <a href="https://github.com/blitz-js/blitz/commits?author=ntgussoni" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/pulls?q=is%3Apr+reviewed-by%3Antgussoni" title="Reviewed Pull Requests">👀</a></td>
<td align="center"><a href="https://github.com/ntgussoni"><img src="https://avatars0.githubusercontent.com/u/10161067?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Nicolas Torres</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=ntgussoni" title="Tests">⚠️</a> <a href="https://github.com/blitz-js/blitz/commits?author=ntgussoni" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/pulls?q=is%3Apr+reviewed-by%3Antgussoni" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/blitz-js/blitz/commits?author=ntgussoni" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="http://simonknott.de"><img src="https://avatars1.githubusercontent.com/u/14912729?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Simon Knott</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Skn0tt" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=Skn0tt" title="Tests">⚠️</a> <a href="#maintenance-Skn0tt" title="Maintenance">🚧</a> <a href="https://github.com/blitz-js/blitz/commits?author=Skn0tt" title="Documentation">📖</a></td>
@@ -572,7 +572,7 @@ Thanks to these wonderful people ([emoji key](https://allcontributors.org/docs/e
<tr>
<td align="center"><a href="jahred.com.au"><img src="https://avatars.githubusercontent.com/u/13903378?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jahred Hope</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=jahredhope" title="Documentation">📖</a></td>
<td align="center"><a href="simonelnahas.github.io/"><img src="https://avatars.githubusercontent.com/u/29279201?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Simon El Nahas</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=simonelnahas" title="Documentation">📖</a></td>
<td align="center"><a href="www.usertrack.net"><img src="https://avatars.githubusercontent.com/u/1384885?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Buleandra Cristian</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Cristy94" title="Documentation">📖</a></td>
<td align="center"><a href="www.usertrack.net"><img src="https://avatars.githubusercontent.com/u/1384885?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Buleandra Cristian</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Cristy94" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=Cristy94" title="Code">💻</a></td>
<td align="center"><a href="http://palauisaac.me/"><img src="https://avatars.githubusercontent.com/u/12257885?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Pedro Enrique Palau Isaac</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=peterpalau" title="Code">💻</a></td>
<td align="center"><a href="www.seanbrydon.me"><img src="https://avatars.githubusercontent.com/u/55134778?v=4?s=100" width="100px;" alt=""/><br /><sub><b>sean-brydon</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=sean-brydon" title="Documentation">📖</a></td>
<td align="center"><a href="buonerba.dev"><img src="https://avatars.githubusercontent.com/u/28837891?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Alessandro</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Dieman89" title="Documentation">📖</a></td>
@@ -630,6 +630,12 @@ Thanks to these wonderful people ([emoji key](https://allcontributors.org/docs/e
<td align="center"><a href="dbachrach.com"><img src="https://avatars.githubusercontent.com/u/45016?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dustin Bachrach</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=dbachrach" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=dbachrach" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/ashikka"><img src="https://avatars.githubusercontent.com/u/58368421?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ashikka Gupta</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=ashikka" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=ashikka" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/deini"><img src="https://avatars.githubusercontent.com/u/2752665?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Daniel Almaguer</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=deini" title="Documentation">📖</a></td>
<td align="center"><a href="https://www.kevinpeters.net/about/"><img src="https://avatars.githubusercontent.com/u/12736734?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kevin Peters</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=igeligel" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="http://anolilab.de"><img src="https://avatars.githubusercontent.com/u/2716058?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Daniel Bannert</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=prisis" title="Code">💻</a></td>
<td align="center"><a href="https://benjakugler96.github.io/"><img src="https://avatars.githubusercontent.com/u/53273645?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Benja Kugler</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=benjakugler96" title="Code">💻</a></td>
<td align="center"><a href="https://semeniuc.ml/"><img src="https://avatars.githubusercontent.com/u/3838856?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Eric Semeniuc</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=esemeniuc" title="Tests">⚠️</a> <a href="https://github.com/blitz-js/blitz/commits?author=esemeniuc" title="Code">💻</a></td>
</tr>
</table>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -23,7 +23,7 @@ const NewProjectPage: BlitzPage = () => {
onSubmit={async (values) => {
try {
const project = await createProjectMutation(values)
router.push(`/projects/${project.id}`)
router.push(Routes.ShowProjectPage({projectId: project.id}))
} catch (error) {
console.error(error)
return {

View File

@@ -12,16 +12,8 @@ import {
} from "blitz"
import getUser from "app/users/queries/getUser"
import logout from "app/auth/mutations/logout"
import path from "path"
export const getServerSideProps: GetServerSideProps = async ({req, res}) => {
// Ensure these files are not eliminated by trace-based tree-shaking (like Vercel)
// https://github.com/blitz-js/blitz/issues/794
path.resolve("next.config.js")
path.resolve("blitz.config.js")
path.resolve(".next/blitz/db.js")
// End anti-tree-shaking
const session = await getSession(req, res)
console.log("Session id:", session.userId)
try {

View File

@@ -29,14 +29,14 @@
},
"dependencies": {
"@prisma/client": "2.24.1",
"blitz": "0.37.0",
"blitz": "0.38.3-canary.1",
"final-form": "4.20.1",
"passport-auth0": "1.4.0",
"passport-github2": "0.1.12",
"passport-twitter": "1.0.4",
"prisma": "2.24.1",
"react": "0.0.0-experimental-6a589ad71",
"react-dom": "0.0.0-experimental-6a589ad71",
"react": "18.0.0-alpha-ed6c091fe-20210701",
"react-dom": "18.0.0-alpha-ed6c091fe-20210701",
"react-final-form": "6.5.2"
},
"devDependencies": {
@@ -48,7 +48,7 @@
"@types/passport-github2": "1.2.4",
"@types/passport-twitter": "1.0.36",
"@types/preview-email": "2.0.0",
"@types/react": "17.0.2",
"@types/react": "17.0.13",
"cross-env": "7.0.3",
"cypress": "6.2.1",
"eslint": "7.21.0",

View File

@@ -31,11 +31,11 @@
},
"dependencies": {
"@prisma/client": "2.24.1",
"blitz": "0.37.0",
"blitz": "0.38.3-canary.1",
"final-form": "4.20.1",
"prisma": "2.24.1",
"react": "0.0.0-experimental-6a589ad71",
"react-dom": "0.0.0-experimental-6a589ad71",
"react": "18.0.0-alpha-ed6c091fe-20210701",
"react-dom": "18.0.0-alpha-ed6c091fe-20210701",
"react-final-form": "6.5.2",
"secure-password": "4.0.0"
},
@@ -43,7 +43,7 @@
"@cypress/skip-test": "2.6.0",
"@testing-library/react": "11.2.5",
"@testing-library/react-hooks": "^4.0.1",
"@types/react": "17.0.2",
"@types/react": "17.0.13",
"@types/secure-password": "3.1.0",
"cypress": "6.2.1",
"eslint": "7.21.0",

View File

@@ -28,18 +28,18 @@
]
},
"dependencies": {
"blitz": "0.37.0",
"blitz": "0.38.3-canary.1",
"final-form": "4.20.1",
"graphql": "15.5.0",
"graphql-request": "3.4.0",
"react": "0.0.0-experimental-6a589ad71",
"react-dom": "0.0.0-experimental-6a589ad71",
"react": "18.0.0-alpha-ed6c091fe-20210701",
"react-dom": "18.0.0-alpha-ed6c091fe-20210701",
"react-final-form": "6.5.2"
},
"devDependencies": {
"@testing-library/react": "11.2.5",
"@testing-library/react-hooks": "^4.0.1",
"@types/react": "17.0.2",
"@types/react": "17.0.13",
"@types/secure-password": "3.1.0",
"babel-eslint": "~10.1.0",
"eslint": "7.21.0",

View File

@@ -26,14 +26,14 @@
]
},
"dependencies": {
"blitz": "0.37.0",
"blitz": "0.38.3-canary.1",
"knex": "0.21.16",
"react": "0.0.0-experimental-6a589ad71",
"react-dom": "0.0.0-experimental-6a589ad71",
"react": "18.0.0-alpha-ed6c091fe-20210701",
"react-dom": "18.0.0-alpha-ed6c091fe-20210701",
"sqlite3": "5.0.2"
},
"devDependencies": {
"@types/react": "17.0.2",
"@types/react": "17.0.13",
"babel-eslint": "~10.1.0",
"eslint": "7.21.0",
"eslint-config-react-app": "~6.0.0",

View File

@@ -33,10 +33,10 @@
},
"dependencies": {
"@prisma/client": "2.24.1",
"blitz": "0.37.0",
"blitz": "0.38.3-canary.1",
"prisma": "2.24.1",
"react": "0.0.0-experimental-6a589ad71",
"react-dom": "0.0.0-experimental-6a589ad71"
"react": "18.0.0-alpha-ed6c091fe-20210701",
"react-dom": "18.0.0-alpha-ed6c091fe-20210701"
},
"devDependencies": {
"babel-eslint": "~10.1.0",

View File

@@ -33,16 +33,16 @@
},
"dependencies": {
"@prisma/client": "2.24.1",
"blitz": "0.37.0",
"blitz": "0.38.3-canary.1",
"final-form": "4.20.1",
"prisma": "2.24.1",
"react": "0.0.0-experimental-6a589ad71",
"react-dom": "0.0.0-experimental-6a589ad71",
"react": "18.0.0-alpha-ed6c091fe-20210701",
"react-dom": "18.0.0-alpha-ed6c091fe-20210701",
"react-final-form": "6.5.2"
},
"devDependencies": {
"@types/preview-email": "2.0.0",
"@types/react": "17.0.2",
"@types/react": "17.0.13",
"eslint": "7.21.0",
"husky": "5.1.2",
"lint-staged": "10.5.4",

View File

@@ -21,15 +21,15 @@
},
"dependencies": {
"@prisma/client": "2.24.1",
"blitz": "0.37.0",
"blitz": "0.38.3-canary.1",
"final-form": "4.20.1",
"prisma": "2.24.1",
"react": "0.0.0-experimental-6a589ad71",
"react-dom": "0.0.0-experimental-6a589ad71",
"react": "18.0.0-alpha-ed6c091fe-20210701",
"react-dom": "18.0.0-alpha-ed6c091fe-20210701",
"react-final-form": "6.5.2"
},
"devDependencies": {
"@types/react": "17.0.2",
"@types/react": "17.0.13",
"cypress": "6.2.1",
"start-server-and-test": "1.11.7"
}

View File

@@ -1,5 +1,5 @@
{
"version": "0.37.0",
"version": "0.38.3-canary.1",
"packages": ["packages/*"],
"npmClient": "yarn",
"useWorkspaces": true,

4
nextjs/.alexignore Normal file
View File

@@ -0,0 +1,4 @@
CODE_OF_CONDUCT.md
docs/
errors/
examples/

View File

@@ -6,7 +6,7 @@
[subrepo]
remote = git@github.com:blitz-js/next.js.git
branch = canary
commit = 8d1a527b8f32fbbc1fde06ce64d3ffd0206acc5d
parent = e4e3e757bccea5361c6d986ad09a085e5bed0cf3
commit = 4be32b7a54fa68dfcf66d4a5cc7744409c409c7f
parent = 194a3720ce56aa3fabace4b07c5faeac1121b8d6
method = merge
cmdver = 0.4.3

View File

@@ -46,7 +46,7 @@ Running a specific test suite inside of the `test/integration` directory:
yarn testonly --testPathPattern "production"
```
Running just one test in the `production` test suite:
Running one test in the `production` test suite:
```sh
yarn testonly --testPathPattern "production" -t "should allow etag header support"

View File

@@ -52,6 +52,9 @@ module.exports = {
{
domain: 'example.fr',
defaultLocale: 'fr',
// an optional http field can also be used to test
// locale domains locally with http instead of https
http: true,
},
],
},

View File

@@ -0,0 +1,139 @@
---
description: Improve the security of your Next.js application by adding HTTP response headers.
---
# Security Headers
To improve the security of your application, you can use [`headers`](/docs/api-reference/next.config.js/headers.md) in `next.config.js` to apply HTTP response headers to all routes in your application.
```jsx
// next.config.js
// You can choose which headers to add to the list
// after learning more below.
const securityHeaders = []
module.exports = {
async headers() {
return [
{
// Apply these headers to all routes in your application.
source: '/(.*)',
headers: securityHeaders,
},
]
},
}
```
## Options
### [X-DNS-Prefetch-Control](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-DNS-Prefetch-Control)
This header controls DNS prefetching, allowing browsers to proactively perform domain name resolution on external links, images, CSS, JavaScript, and more. This prefetching is performed in the background, so the [DNS](https://developer.mozilla.org/en-US/docs/Glossary/DNS) is more likely to be resolved by the time the referenced items are needed. This reduces latency when the user clicks a link.
```jsx
{
key: 'X-DNS-Prefetch-Control',
value: 'on'
}
```
### [Strict-Transport-Security](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security)
This header informs browsers it should only be accessed using HTTPS, instead of using HTTP. Using the configuration below, all present and future subdomains will use HTTPS for a `max-age` of 2 years. This blocks access to pages or subdomains that can only be served over HTTP.
If you're deploying to [Vercel](https://vercel.com/docs/edge-network/headers#strict-transport-security), this header is not necessary as it's automatically added to all deployments.
```jsx
{
key: 'Strict-Transport-Security',
value: 'max-age=31536000; includeSubDomains; preload'
}
```
### [X-XSS-Protection](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection)
This header stops pages from loading when they detect reflected cross-site scripting (XSS) attacks. Although this protection is not necessary when sites implement a strong [`Content-Security-Policy`](#content-security-policy) disabling the use of inline JavaScript (`'unsafe-inline'`), it can still provide protection for older web browsers that don't support CSP.
```jsx
{
key: 'X-XSS-Protection',
value: '1; mode=block'
}
```
### [X-Frame-Options](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options)
This header indicates whether the site should be allowed to be displayed within an `iframe`. This can prevent against clickjacking attacks. This header has been superseded by CSP's `frame-ancestors` option, which has better support in modern browsers.
```jsx
{
key: 'X-Frame-Options',
value: 'SAMEORIGIN'
}
```
### [Permissions-Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy)
This header allows you to control which features and APIs can be used in the browser. It was previously named `Feature-Policy`. You can view the full list of permission options [here](https://www.w3.org/TR/permissions-policy-1/).
```jsx
{
key: 'Permissions-Policy',
value: 'camera=(), microphone=(), geolocation=(), interest-cohort=()'
}
```
### [X-Content-Type-Options](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options)
This header prevents the browser from attempting to guess the type of content if the `Content-Type` header is not explicitly set. This can prevent XSS exploits for websites that allow users to upload and share files. For example, a user trying to download an image, but having it treated as a different `Content-Type` like an executable, which could be malicious. This header also applies to downloading browser extensions. The only valid value for this header is `nosniff`.
```jsx
{
key: 'X-Content-Type-Options',
value: 'nosniff'
}
```
### [Referrer-Policy](https://scotthelme.co.uk/a-new-security-header-referrer-policy/)
This header controls how much information the browser includes when navigating from the current website (origin) to another. You can read about the different options [here](https://scotthelme.co.uk/a-new-security-header-referrer-policy/).
```jsx
{
key: 'Referrer-Policy',
value: 'origin-when-cross-origin'
}
```
### [Content-Security-Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP)
This header helps prevent cross-site scripting (XSS), clickjacking and other code injection attacks. Content Security Policy (CSP) can specify allowed origins for content including scripts, stylesheets, images, fonts, objects, media (audio, video), iframes, and more.
You can read about the many different CSP options [here](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP).
```jsx
{
key: 'Content-Security-Policy',
value: // Your CSP Policy
}
```
### References
- [MDN](https://developer.mozilla.org)
- [Varun Naik](https://blog.vnaik.com/posts/web-attacks.html)
- [Scott Helme](https://scotthelme.co.uk)
- [Mozilla Observatory](https://observatory.mozilla.org/)
## Related
For more information, we recommend the following sections:
<div class="card">
<a href="/docs/api-reference/next.config.js/headers.md">
<b>Headers:</b>
<small>Add custom HTTP headers to your Next.js app.</small>
</a>
</div>

View File

@@ -27,8 +27,7 @@ yarn create next-app --typescript
- **--ts, --typescript** - Initialize as a TypeScript project.
- **-e, --example [name]|[github-url]** - An example to bootstrap the app with. You can use an example name from the [Next.js repo](https://github.com/vercel/next.js/tree/master/examples) or a GitHub URL. The URL can use any branch and/or subdirectory.
- **--example-path [path-to-example]** - In a rare case, your GitHub URL might contain a branch name with a slash (e.g. bug/fix-1) and the path to the example (e.g. foo/bar). In this case, you must specify the path to the example separately: `--example-path foo/bar`
- **--use-npm** - Explicitly tell the CLI to bootstrap the app using npm. To bootstrap using yarn we recommend to run `yarn create next-app`
- **--typescript or --ts** - Creates the default template with TypeScript instead of JavaScript.
- **--use-npm** - Explicitly tell the CLI to bootstrap the app using npm. To bootstrap using yarn we recommend running `yarn create next-app`
### Why use Create Next App?

View File

@@ -373,3 +373,14 @@ module.exports = {
### Cache-Control
Cache-Control headers set in next.config.js will be overwritten in production to ensure that static assets can be cached effectively. If you need to revalidate the cache of a page that has been [statically generated](https://nextjs.org/docs/basic-features/pages#static-generation-recommended), you can do so by setting `revalidate` in the page's [`getStaticProps`](https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation) function.
## Related
For more information, we recommend the following sections:
<div class="card">
<a href="/docs/advanced-features/security-headers.md">
<b>Security Headers:</b>
<small>Improve the security of your Next.js application by add HTTP response headers.</small>
</a>
</div>

View File

@@ -14,12 +14,12 @@ description: Enable Image Optimization with the built-in Image component.
<details>
<summary><b>Version History</b></summary>
| Version | Changes |
| --------- | ---------------------------------------------------------------------------- |
| `v11.0.0` | Added static imports for `src`. Added `placeholder` and `blurDataURL` props. |
| `v10.0.5` | `loader` prop added. |
| `v10.0.1` | `layout` prop added. |
| `v10.0.0` | `next/image` introduced. |
| Version | Changes |
| --------- | ------------------------------------------------------------------------------------------------- |
| `v11.0.0` | `src` prop support for static import.<br/>`placeholder` prop added.<br/>`blurDataURL` prop added. |
| `v10.0.5` | `loader` prop added. |
| `v10.0.1` | `layout` prop added. |
| `v10.0.0` | `next/image` introduced. |
</details>
@@ -40,7 +40,7 @@ We can serve an optimized image like so:
```jsx
import Image from 'next/image'
import profilePic from '../me.png'
import profilePic from '../public/me.png'
function Home() {
return (
@@ -166,7 +166,17 @@ Should only be used when the image is visible above the fold. Defaults to
### placeholder
A placeholder to use while the image is loading, possible values are `blur` or `empty`. Defaults to `empty`.
When `placeholder="blur"`, the `blurDataURL` will be used as the placeholder. If the `src` is an object from a static import, then `blurDataURL` will automatically be populated. If the `src` is a string, then you must provide the [`blurDataURL` property](#blurdataurl).
When `blur`, the [`blurDataURL`](#blurdataurl) property will be used as the placeholder. If `src` is an object from a static import and the imported image is jpg, png, or webp, then `blurDataURL` will automatically be populated.
For dynamic images, you must provide the [`blurDataURL`](#blurdataurl) property. Solutions such as [Plaiceholder](https://github.com/joe-bell/plaiceholder) can help with `base64` generation.
When `empty`, there will be no placeholder while the image is loading, only empty space.
Try it out:
- [Demo the `blur` placeholder](https://image-component.nextjs.gallery/placeholder)
- [Demo the shimmer effect with `blurDataURL` prop](https://image-component.nextjs.gallery/shimmer)
## Advanced Props
@@ -211,6 +221,13 @@ with [`placeholder="blur"`](#placeholder).
Must be a base64-encoded image. It will be enlarged and blurred, so a very small image (10px or
less) is recommended. Including larger images as placeholders may harm your application performance.
Try it out:
- [Demo the default `blurDataURL` prop](https://image-component.nextjs.gallery/placeholder)
- [Demo the shimmer effect with `blurDataURL` prop](https://image-component.nextjs.gallery/shimmer)
You can also [generate a solid color Data URL](https://png-pixel.com) to match the image.
### unoptimized
When true, the source image will be served as-is instead of changing quality,

View File

@@ -49,6 +49,7 @@ The following is the definition of the `router` object returned by both [`useRou
- `locale`: `String` - The active locale (if enabled).
- `locales`: `String[]` - All supported locales (if enabled).
- `defaultLocale`: `String` - The current default locale (if enabled).
- `domainLocales`: `Array<{domain, defaultLocale, locales}>` - Any configured domain locales.
- `isReady`: `boolean` - Whether the router fields are updated client-side and ready for use. Should only be used inside of `useEffect` methods and not for conditionally rendering on the server.
- `isPreview`: `boolean` - Whether the application is currently in [preview mode](/docs/advanced-features/preview-mode.md).
@@ -112,6 +113,8 @@ export default function Page() {
}
```
> **Note:** When navigating to the same page in Next.js, the page's state **will not** be reset by default, as the top-level React component is the same. You can manually ensure the state is updated using `useEffect`.
Redirecting the user to `pages/login.js`, useful for pages behind [authentication](/docs/authentication):
```jsx

View File

@@ -149,6 +149,16 @@ A stricter `next/core-web-vitals` rule set can also be added in `.eslintrc`:
> Both `next` and `next/core-web-vitals` entry points are automatically included for new applications built with [Create Next App](/docs/api-reference/create-next-app.md).
## Usage with Prettier
ESLint also contains code formatting rules, which can conflict with your existing [Prettier](https://prettier.io/) setup. We recommend including [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier) in your ESLint config to make ESLint and Prettier work together.
```js
{
"extends": ["next", "prettier"]
}
```
## Migrating Existing Config
If you already have ESLint configured in your application, we recommend extending directly from the Next.js ESLint plugin instead of the shareable configuration.

View File

@@ -50,6 +50,39 @@ function Home() {
export default Home
```
## Image Imports
You can `import` images that live in your project. (Note that `require` is not supported—only `import`.)
With direct `import`s, `width`, `height`, and `blurDataURL` will be automatically provided to the image component. Alt text is still needed separately.
```js
import Image from 'next/image'
import profilePic from '../public/me.png'
function Home() {
return (
<>
<h1>My Homepage</h1>
<Image
src={profilePic}
alt="Picture of the author"
// width={500} automatically provided
// height={500} automatically provided
// blurDataURL="data:..." automatically provided
// Optionally allows to add a blurred version of the image while loading
// placeholder="blur"
/>
<p>Welcome to my homepage!</p>
</>
)
}
```
For dynamic or remote images, you'll have to provide [`width`](/docs/api-reference/next/image#width), [`height`](/docs/api-reference/next/image#height) and [`blurDataURL`](/docs/api-reference/next/image#blurdataurl) manually.
## Properties
[View all properties](/docs/api-reference/next/image.md) available to the `next/image` component.
## Configuration
@@ -138,6 +171,22 @@ module.exports = {
}
```
### Disable Static Imports
The default behavior allows you to import static files such as `import icon from './icon.png` and then pass that to the `src` property.
In some cases, you may wish to disable this feature if it conflicts with other plugins that expect the import to behave differently.
You can disable static image imports with the following configuration below.
```js
module.exports = {
images: {
disableStaticImages: true,
},
}
```
## Related
For more information on what to do next, we recommend the following sections:

View File

@@ -4,89 +4,126 @@ description: Next.js helps you optimize loading third-party scripts with the bui
# Script Component
Since version **11**, Next.js has a built-in Script component.
<details>
<summary><b>Version History</b></summary>
Example of usage
| Version | Changes |
| --------- | ------------------------- |
| `v11.0.0` | `next/script` introduced. |
</details>
The Next.js Script component enables developers to set the loading priority of third-party scripts to save developer time and improve loading performance.
Websites often need third parties for things like analytics, ads, customer support widgets, and consent management. However, these scripts tend to be heavy on loading performance and can drag down the user experience. Developers often struggle to decide where to place them in an application for optimal loading.
With `next/script`, you can define the `strategy` property and Next.js will optimize loading for the script:
- `beforeInteractive`: For critical scripts that need to be fetched and executed **before** the page is interactive, such as bot detection and consent management. These scripts are injected into the initial HTML from the server and run before self-bundled JavaScript is executed.
- `afterInteractive` (**default**): For scripts that can fetch and execute **after** the page is interactive, such as tag managers and analytics. These scripts are injected on the client-side and will run after hydration.
- `lazyOnload` For scripts that can wait to load during idle time, such as chat support and social media widgets.
> **Note:** These loading strategies work the same for inline scripts wrapped with `<Script>`. See the inline scripts example below.
## Usage
Previously, you needed to define `script` tags inside the `Head` of your Next.js page.
```js
// Before
// pages/index.js
import Head from 'next/head'
function Home() {
return (
<>
<Head>
<script async src="https://www.google-analytics.com/analytics.js" />
</Head>
</>
)
}
```
With `next/script`, you no longer need to wrap scripts in `next/head`. Further, `next/script` should **not** be used in `pages/_document.js` as `next/script` has client-side functionality to ensure loading order. For example:
```js
// After
// pages/index.js
import Script from 'next/script'
function Home() {
return (
<>
<Script src="https://www.google-analytics.com/analytics.js" />
</>
)
}
```
## Examples
### Loading Polyfills
```js
import Script from 'next/script'
// Before
<Script
async
src="https://www.google-analytics.com/analytics.js"
/>
// After
<Script
src="https://www.google-analytics.com/analytics.js"
;<Script
src="https://polyfill.io/v3/polyfill.min.js?features=IntersectionObserverEntry%2CIntersectionObserver"
strategy="beforeInteractive"
/>
```
Three loading strategies will be initially supported for wrapping third-party scripts:
### Lazy-Loading
- beforeInteractive
- script is fetched and executed _before_ page is interactive (i.e. before self-bundled javascript is executed)
- script is injected in SSRs HTML - similar to self-bundled JS
- afterInteractive (**default**)
- script is fetched and executed _after_ page is interactive (i.e. after self-bundled javascript is executed)
- script is injected during hydration and will execute soon after hydration
- lazyOnload
- script is injected at onload, and will execute in a subsequent idle period (using `requestIdleCallback`)
```js
import Script from 'next/script'
;<Script
src="https://connect.facebook.net/en_US/sdk.js"
strategy="lazyOnload"
/>
```
NOTE: above strategies work the same for inline scripts wrapped with ScriptLoader.
### Executing Code After Loading (`onLoad`)
Example scenarios
```js
import Script from 'next/script'
;<Script
id="stripe-js"
src="https://js.stripe.com/v3/"
onLoad={() => {
this.setState({ stripe: window.Stripe('pk_test_12345') })
}}
/>
```
### Inline Scripts
```js
import Script from 'next/script'
// Loading polyfills before-interactive
<Script
src="https://polyfill.io/v3/polyfill.min.js?features=IntersectionObserverEntry%2CIntersectionObserver"
strategy="beforeInteractive"
></Script>
// Lazy load FB scripts
<Script
src="https://connect.facebook.net/en_US/sdk.js"
strategy="lazyOnload"
></Script>
// Use the onLoad callback to execute code on script load
<Script id="stripe-js" src="https://js.stripe.com/v3/" onLoad={() => {
this.setState({stripe: window.Stripe('pk_test_12345')});
}}></Script>
// Loading strategy works for inline scripts too
<Script strategy="lazyOnload">
{`document.getElementById('banner').removeClass('hidden')`}
</Script>
// or
<Script
dangerouslySetInnerHTML={{
__html: `document.getElementById('banner').removeClass('hidden')`,
__html: `document.getElementById('banner').removeClass('hidden')`
}}
>
</Script>
/>
```
// All script attributes are forwarded to the final element
<Script
### Forwarding Attributes
```js
import Script from 'next/script'
;<Script
src="https://www.google-analytics.com/analytics.js"
id="analytics"
nonce="XUENAJFW"
data-test="analytics"
></Script>
/>
```
## Which third-party scripts to wrap with Script Loader
We recommend the following Script Loader strategies for these categories of third-party scripts
| Loading strategy | third-party categories |
| ----------------- | -------------------------------------------------------------------------------------------- |
| beforeInteractive | polyfill.io<br>Bot detection, security & authentication<br>User consent management (GDPR) |
| afterInteractive | Tag-managers<br>Analytics |
| lazyOnload | customer relationship management eg. Google feedback, chat support widget<br>social networks |

View File

@@ -52,6 +52,10 @@
{
"title": "Supported Browsers and Features",
"path": "/docs/basic-features/supported-browsers-features.md"
},
{
"title": "Script",
"path": "/docs/basic-features/script.md"
}
]
},
@@ -204,6 +208,10 @@
{
"title": "Internationalized Routing",
"path": "/docs/advanced-features/i18n-routing.md"
},
{
"title": "Security Headers",
"path": "/docs/advanced-features/security-headers.md"
}
]
},

View File

@@ -6,7 +6,7 @@ description: Learn how to upgrade Next.js.
## Upgrading from version 10 to 11
## Upgrade React version to latest
### Upgrade React version to latest
Most applications already use the latest version of React, with Next.js 11 the minimum React version has been updated to 17.0.2.
@@ -22,6 +22,20 @@ Or using `yarn`:
yarn add react@latest react-dom@latest
```
### Upgrade Next.js version to latest
To upgrade you can run the following command in the terminal:
```
npm install next@latest
```
or
```
yarn add next@latest
```
### Webpack 5
Webpack 5 is now the default for all Next.js applications. If you did not have custom webpack configuration your application is already using webpack 5. If you do have custom webpack configuration you can refer to the [Next.js webpack 5 documentation](https://nextjs.org/docs/messages/webpack5) for upgrading guidance.
@@ -128,7 +142,13 @@ There were no breaking changes between version 9 and 10.
To upgrade run the following command:
```
npm install next@latest
npm install next@10
```
Or using `yarn`:
```
yarn add next@10
```
## Upgrading from version 8 to 9

View File

@@ -6,7 +6,7 @@ The `future.webpack5` option has been moved to `webpack5` in `next.config.js`.
#### Possible Ways to Fix It
If you had the value `true` you can removed the option as webpack 5 is now the default for all Next.js apps unless opted out.
If you had the value `true` you can remove the option as webpack 5 is now the default for all Next.js apps unless opted out.
If you had he value `false` you can update `next.config.js`:

View File

@@ -373,7 +373,28 @@
"path": "/errors/undefined-webpack-config.md"
},
{ "title": "url-deprecated", "path": "/errors/url-deprecated.md" },
{ "title": "webpack5", "path": "/errors/webpack5.md" }
{ "title": "webpack5", "path": "/errors/webpack5.md" },
{
"title": "client-side-exception-occurred",
"path": "/errors/client-side-exception-occurred.md"
},
{
"title": "future-webpack5-moved-to-webpack5",
"path": "/errors/future-webpack5-moved-to-webpack5.md"
},
{
"title": "link-multiple-children",
"path": "/errors/link-multiple-children.md"
},
{ "title": "no-img-element", "path": "/errors/no-img-element.md" },
{
"title": "non-dynamic-getstaticpaths-usage",
"path": "/errors/non-dynamic-getstaticpaths-usage.md"
},
{
"title": "placeholder-blur-data-url",
"path": "/errors/placeholder-blur-data-url.md"
}
]
}
]

View File

@@ -9,7 +9,7 @@ An HTML `<img>` element was used to display an image. For better performance and
Import and use the `<Image />` component:
```jsx
import { Image } from 'next/image'
import Image from 'next/image'
function Home() {
return (

View File

@@ -11,7 +11,7 @@ A synchronous script was used which can impact your webpage's performance.
Use the Script component with the right loading strategy to defer loading of the script until necessary.
```jsx
import Script from 'next/experimental-script'
import Script from 'next/script'
const Home = () => {
return (
@@ -25,8 +25,6 @@ const Home = () => {
export default Home
```
Note: This is still an experimental feature and needs to be enabled via the `experimental.scriptLoader` flag in `next.config.js`.
### Useful Links
- [Efficiently load third-party JavaScript](https://web.dev/efficiently-load-third-party-javascript/)

View File

@@ -17,5 +17,5 @@
"registry": "https://registry.npmjs.org/"
}
},
"version": "11.0.0"
"version": "11.0.1"
}

View File

@@ -24,8 +24,9 @@
"lint-typescript": "lerna run typescript",
"lint-eslint": "eslint . --ext js,jsx,ts,tsx --max-warnings=0",
"lint-no-typescript": "run-p prettier-check lint-eslint",
"lint": "run-p lint-typescript prettier-check lint-eslint",
"lint": "run-p lint-typescript prettier-check lint-eslint lint-language",
"lint-fix": "yarn prettier-fix && eslint . --ext js,jsx,ts,tsx --fix --max-warnings=0",
"lint-language": "alex .",
"prettier-check": "prettier --check .",
"prettier-fix": "prettier --write .",
"types": "lerna run types --stream",
@@ -44,6 +45,7 @@
"@babel/preset-react": "7.12.10",
"@fullhuman/postcss-purgecss": "1.3.0",
"@mdx-js/loader": "0.18.0",
"@svgr/webpack": "5.5.0",
"@testing-library/react": "11.2.5",
"@types/cheerio": "0.22.16",
"@types/fs-extra": "8.1.0",
@@ -56,6 +58,7 @@
"@zeit/next-sass": "1.0.2-canary.2",
"@zeit/next-typescript": "1.1.2-canary.0",
"abort-controller": "3.0.0",
"alex": "9.1.0",
"amphtml-validator": "1.0.33",
"async-sema": "3.0.1",
"babel-core": "7.0.0-bridge.0",
@@ -80,6 +83,7 @@
"eslint-plugin-react-hooks": "^4.2.0",
"execa": "2.0.3",
"express": "4.17.0",
"faker": "5.5.3",
"faunadb": "2.6.1",
"firebase": "7.14.5",
"fs-extra": "^9.1.0",
@@ -112,8 +116,8 @@
"prettier": "2.2.1",
"pretty-bytes": "5.3.0",
"pretty-ms": "7.0.0",
"react": "0.0.0-experimental-6a589ad71",
"react-dom": "0.0.0-experimental-6a589ad71",
"react": "18.0.0-alpha-ed6c091fe-20210701",
"react-dom": "18.0.0-alpha-ed6c091fe-20210701",
"react-ssr-prepass": "1.0.8",
"release": "6.3.0",
"request-promise-core": "1.1.2",

View File

@@ -1,6 +1,6 @@
# Create Next App
The easiest way to get started with Next.js is by using `create-next-app`. This simple CLI tool enables you to quickly start building a new Next.js application, with everything set up for you. You can create a new app using the default Next.js template, or by using one of the [official Next.js examples](https://github.com/vercel/next.js/tree/canary/examples). To get started, use the following command:
The easiest way to get started with Next.js is by using `create-next-app`. This CLI tool enables you to quickly start building a new Next.js application, with everything set up for you. You can create a new app using the default Next.js template, or by using one of the [official Next.js examples](https://github.com/vercel/next.js/tree/canary/examples). To get started, use the following command:
```bash
npx create-next-app

View File

@@ -1,7 +1,7 @@
{
"private": true,
"name": "create-next-app",
"version": "11.0.0",
"version": "11.0.1",
"keywords": [
"react",
"next",
@@ -44,7 +44,7 @@
"prompts": "2.1.0",
"rimraf": "3.0.0",
"tar": "4.4.10",
"typescript": "4.1.5",
"typescript": "4.3.4",
"update-check": "1.5.4",
"validate-npm-package-name": "3.0.0"
},

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -58,6 +58,9 @@ module.exports = {
[require.resolve('eslint-import-resolver-node')]: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
[require.resolve('eslint-import-resolver-typescript')]: {
alwaysTryTypes: true,
},
},
},
}

View File

@@ -1,7 +1,7 @@
{
"name": "eslint-config-next",
"private": "true",
"version": "11.0.0",
"version": "11.0.1",
"description": "ESLint configuration used by NextJS.",
"main": "index.js",
"license": "MIT",
@@ -10,10 +10,11 @@
"directory": "packages/eslint-config-next"
},
"dependencies": {
"@next/eslint-plugin-next": "11.0.0",
"@next/eslint-plugin-next": "11.0.1",
"@rushstack/eslint-patch": "^1.0.6",
"@typescript-eslint/parser": "^4.20.0",
"eslint-import-resolver-node": "^0.3.4",
"eslint-import-resolver-typescript": "^2.4.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jsx-a11y": "^6.4.1",
"eslint-plugin-react": "^7.23.1",

View File

@@ -44,9 +44,7 @@ module.exports = {
const hasAnchorChild = children.some(
(attr) =>
attr.type === 'JSXElement' &&
attr.openingElement.name.name === 'a' &&
attr.closingElement.name.name === 'a'
attr.type === 'JSXElement' && attr.openingElement.name.name === 'a'
)
if (!hasAnchorChild && !hasPassHref) {
@@ -56,7 +54,7 @@ module.exports = {
attributes.value('passHref') !== true
? 'must be set to true'
: 'is missing'
}. See https://nextjs.org/docs/messages/link-passhref.`,
}. See https://nextjs.org/docs/messages/link-passhref`,
})
}
},

View File

@@ -21,7 +21,7 @@ module.exports = {
context.report({
node,
message: `Do not use <img>. Use Image from 'next/image' instead. See https://nextjs.org/docs/messages/no-img-element.`,
message: `Do not use <img>. Use <Image> from 'blitz' instead. See https://nextjs.org/docs/messages/no-img-element.`,
})
},
}

View File

@@ -1,7 +1,7 @@
{
"private": true,
"name": "@next/eslint-plugin-next",
"version": "11.0.0",
"version": "11.0.1",
"description": "ESLint plugin for NextJS.",
"main": "lib/index.js",
"license": "MIT",

View File

@@ -1,7 +1,7 @@
{
"private": true,
"name": "@next/bundle-analyzer",
"version": "11.0.0",
"version": "11.0.1",
"main": "index.js",
"license": "MIT",
"repository": {

View File

@@ -0,0 +1,34 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env.local
.env.development.local
.env.test.local
.env.production.local
# vercel
.vercel

View File

@@ -1,5 +1,5 @@
// @ts-ignore internal module
import Runner from 'jscodeshift/src/runner'
import Runner from 'jscodeshift/src/Runner'
export default function runJscodeshift(
transformerPath: string,

View File

@@ -1,7 +1,7 @@
{
"private": true,
"name": "@next/codemod",
"version": "11.0.0",
"version": "11.0.1",
"license": "MIT",
"dependencies": {
"chalk": "4.1.0",

View File

@@ -1,7 +1,7 @@
{
"private": true,
"name": "@next/env",
"version": "11.0.0",
"version": "11.0.1",
"keywords": [
"react",
"next",

View File

@@ -1,7 +1,7 @@
{
"private": true,
"name": "@next/mdx",
"version": "11.0.0",
"version": "11.0.1",
"main": "index.js",
"license": "MIT",
"repository": {

View File

@@ -1,7 +1,7 @@
{
"private": true,
"name": "@next/plugin-storybook",
"version": "11.0.0",
"version": "11.0.1",
"repository": {
"url": "vercel/next.js",
"directory": "packages/next-plugin-storybook"

View File

@@ -1,7 +1,7 @@
{
"private": true,
"name": "@next/polyfill-module",
"version": "11.0.0",
"version": "11.0.1",
"description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)",
"main": "dist/polyfill-module.js",
"license": "MIT",

View File

@@ -1,7 +1,7 @@
{
"private": true,
"name": "@next/polyfill-nomodule",
"version": "11.0.0",
"version": "11.0.1",
"description": "A polyfill for non-dead, nomodule browsers.",
"main": "dist/polyfill-nomodule.js",
"license": "MIT",

View File

@@ -1,10 +1,12 @@
import { readFileSync } from 'fs'
import JSON5 from 'next/dist/compiled/json5'
import { createConfigItem, loadOptions } from 'next/dist/compiled/babel/core'
import loadConfig from 'next/dist/compiled/babel/core-lib-config'
import { NextBabelLoaderOptions, NextJsLoaderContext } from './types'
import { consumeIterator } from './util'
import { isPageFile as isPageFileFn } from '../../utils'
const nextDistPath = /(next[\\/]dist[\\/]next-server[\\/]lib)|(next[\\/]dist[\\/]client)|(next[\\/]dist[\\/]pages)/
@@ -42,8 +44,8 @@ function getCacheCharacteristics(
filename: string
): CharacteristicsGermaneToCaching {
const { isServer, pagesDir } = loaderOptions
const isPageFile = filename.startsWith(pagesDir)
const isNextDist = nextDistPath.test(filename)
const isPageFile = !isNextDist && isPageFileFn(filename.replace(pagesDir, ''))
const hasModuleExports = source.indexOf('module.exports') !== -1
const fileExt = fileExtensionRegex.exec(filename)?.[1] || 'unknown'
@@ -151,7 +153,7 @@ const isJsFile = /\.js$/
function getCustomBabelConfig(configFilePath: string) {
if (isJsonFile.exec(configFilePath)) {
const babelConfigRaw = readFileSync(configFilePath, 'utf8')
return JSON.parse(babelConfigRaw)
return JSON5.parse(babelConfigRaw)
} else if (isJsFile.exec(configFilePath)) {
return require(configFilePath)
}

View File

@@ -35,30 +35,39 @@ export default function NoAnonymousDefaultExport({
switch (def.type) {
case 'ArrowFunctionExpression': {
warn(
[
chalk.yellow.bold(
'Anonymous arrow functions cause Fast Refresh to not preserve local component state.'
),
'Please add a name to your function, for example:',
'',
chalk.bold('Before'),
chalk.cyan('export default () => <div />;'),
'',
chalk.bold('After'),
chalk.cyan('const Named = () => <div />;'),
chalk.cyan('export default Named;'),
'',
`A codemod is available to fix the most common cases: ${chalk.cyan(
'https://nextjs.link/codemod-ndc'
)}`,
].join('\n')
)
if (
!process.env.__NEXT_TEST_MODE ||
!!process.env.__NEXT_TEST_ANON_EXPORT
) {
warn(
[
chalk.yellow.bold(
'Anonymous arrow functions cause Fast Refresh to not preserve local component state.'
),
'Please add a name to your function, for example:',
'',
chalk.bold('Before'),
chalk.cyan('export default () => <div />;'),
'',
chalk.bold('After'),
chalk.cyan('const Named = () => <div />;'),
chalk.cyan('export default Named;'),
'',
`A codemod is available to fix the most common cases: ${chalk.cyan(
'https://nextjs.link/codemod-ndc'
)}`,
].join('\n')
)
}
break
}
case 'FunctionDeclaration': {
const isAnonymous = !Boolean(def.id)
if (isAnonymous) {
if (
isAnonymous &&
(!process.env.__NEXT_TEST_MODE ||
!!process.env.__NEXT_TEST_ANON_EXPORT)
) {
warn(
[
chalk.yellow.bold(

View File

@@ -10,6 +10,7 @@ import { ClientPagesLoaderOptions } from './webpack/loaders/next-client-pages-lo
import { ServerlessLoaderQuery } from './webpack/loaders/next-serverless-loader'
import { LoadedEnvFiles } from '@next/env'
import { NextConfig } from '../next-server/server/config'
import { convertPageFilePathToRoutePath } from './utils'
type PagesMapping = {
[page: string]: string
@@ -22,19 +23,19 @@ export function createPagesMapping(
const previousPages: PagesMapping = {}
const pages: PagesMapping = pagePaths.reduce(
(result: PagesMapping, pagePath): PagesMapping => {
let page = `${pagePath
let page = `${convertPageFilePathToRoutePath(pagePath)
.replace(new RegExp(`\\.+(${extensions.join('|')})$`), '')
.replace(/\\/g, '/')}`.replace(/\/index$/, '')
const pageKey = page === '' ? '/' : page
let pageKey = page === '' ? '/' : page
if (pageKey in result) {
warn(
`Duplicate page detected. ${chalk.cyan(
join('pages', previousPages[pageKey])
)} and ${chalk.cyan(
join('pages', pagePath)
)} both resolve to ${chalk.cyan(pageKey)}.`
previousPages[pageKey]
)} and ${chalk.cyan(pagePath)} both resolve to ${chalk.cyan(
pageKey
)}.`
)
} else {
previousPages[pageKey] = pagePath

View File

@@ -15,7 +15,6 @@ import {
PUBLIC_DIR_MIDDLEWARE_CONFLICT,
} from '../lib/constants'
import { fileExists } from '../lib/file-exists'
import { findPagesDir } from '../lib/find-pages-dir'
import loadCustomRoutes, {
CustomRoutes,
getRedirectStatus,
@@ -125,7 +124,7 @@ export default async function build(
const nextBuildSpan = trace('next-build')
return nextBuildSpan.traceAsyncFn(async () => {
// attempt to load global env values so they are available in next.config.js
// attempt to load global env values so they are available in blitz.config.js
const { loadedEnvFiles } = nextBuildSpan
.traceChild('load-dotenv')
.traceFn(() => loadEnvConfig(dir, false, Log))
@@ -162,7 +161,7 @@ export default async function build(
setGlobal('telemetry', telemetry)
const publicDir = path.join(dir, 'public')
const pagesDir = findPagesDir(dir)
const pagesDir = dir
const hasPublicDir = await fileExists(publicDir)
telemetry.record(
@@ -192,7 +191,13 @@ export default async function build(
const verifyResult = await nextBuildSpan
.traceChild('verify-typescript-setup')
.traceAsyncFn(() =>
verifyTypeScriptSetup(dir, pagesDir, !ignoreTypeScriptErrors, cacheDir)
verifyTypeScriptSetup(
dir,
pagesDir,
!ignoreTypeScriptErrors,
!config.images.disableStaticImages,
cacheDir
)
)
const typeCheckEnd = process.hrtime(typeCheckStart)

View File

@@ -18,7 +18,7 @@ import {
SERVER_PROPS_SSG_CONFLICT,
} from '../lib/constants'
import prettyBytes from '../lib/pretty-bytes'
import { recursiveReadDir } from '../lib/recursive-readdir'
import { recursiveFindPages } from '../lib/recursive-readdir'
import { getRouteMatcher, getRouteRegex } from '../next-server/lib/router/utils'
import { isDynamicRoute } from '../next-server/lib/router/utils/is-dynamic'
import escapePathDelimiters from '../next-server/lib/router/utils/escape-path-delimiters'
@@ -49,14 +49,35 @@ const fsStat = (file: string) => {
return (fileStats[file] = fileSize(file))
}
export const topLevelFoldersThatMayContainPages = [
'pages',
'src',
'app',
'integrations',
]
export function convertPageFilePathToRoutePath(filePath: string) {
return filePath
.replace(/^.*?[\\/]pages[\\/]/, '/')
.replace(/^.*?[\\/]api[\\/]/, '/api/')
}
export function isPageFile(filePathFromAppRoot: string) {
return (
/[\\/]pages[\\/]/.test(filePathFromAppRoot) ||
/[\\/]api[\\/]/.test(filePathFromAppRoot)
)
}
export function buildPageExtensionRegex(pageExtensions: string[]) {
return new RegExp(`(?<!\\.test|\\.spec)\\.(?:${pageExtensions.join('|')})$`)
}
export function collectPages(
directory: string,
pageExtensions: string[]
): Promise<string[]> {
return recursiveReadDir(
directory,
new RegExp(`\\.(?:${pageExtensions.join('|')})$`)
)
return recursiveFindPages(directory, buildPageExtensionRegex(pageExtensions))
}
export interface PageInfo {

View File

@@ -3,6 +3,7 @@ import chalk from 'chalk'
import crypto from 'crypto'
import { readFileSync } from 'fs'
import { codeFrameColumns } from 'next/dist/compiled/babel/code-frame'
import semver from 'next/dist/compiled/semver'
import { isWebpack5, webpack } from 'next/dist/compiled/webpack/webpack'
import path, { join as pathJoin, relative as relativePath } from 'path'
import {
@@ -12,6 +13,7 @@ import {
PAGES_DIR_ALIAS,
} from '../lib/constants'
import { fileExists } from '../lib/file-exists'
import { getPackageVersion } from '../lib/get-package-version'
import { CustomRoutes } from '../lib/load-custom-routes.js'
import { getTypeScriptConfiguration } from '../lib/typescript/getTypeScriptConfiguration'
import {
@@ -50,20 +52,7 @@ import WebpackConformancePlugin, {
} from './webpack/plugins/webpack-conformance-plugin'
import { WellKnownErrorsPlugin } from './webpack/plugins/wellknown-errors-plugin'
import { regexLikeCss } from './webpack/config/blocks/css'
import fs from 'fs'
import { getProjectRoot } from '../server/lib/utils'
/* ------ Blitz.js ------- */
function doesDbModuleExist() {
const projectRoot = getProjectRoot()
return (
fs.existsSync(path.join(projectRoot, 'db/index.js')) ||
fs.existsSync(path.join(projectRoot, 'db/index.ts')) ||
fs.existsSync(path.join(projectRoot, 'db/index.tsx'))
)
}
/* ------ Blitz.js ------- */
import { existsSync } from 'fs'
type ExcludesFalse = <T>(x: T | false) => x is T
@@ -244,6 +233,18 @@ export default async function getBaseWebpackConfig(
rewrites.afterFiles.length > 0 ||
rewrites.fallback.length > 0
const hasReactRefresh: boolean = dev && !isServer
const reactDomVersion = await getPackageVersion({
cwd: dir,
name: 'react-dom',
})
const hasReactExperimental: boolean =
Boolean(reactDomVersion) && reactDomVersion!.includes('experimental') // blitz
const hasReact18: boolean =
(Boolean(reactDomVersion) &&
(semver.gte(reactDomVersion!, '18.0.0') ||
semver.coerce(reactDomVersion)?.version === '18.0.0')) ||
hasReactExperimental // blitz
const hasReactRoot: boolean = config.experimental.reactRoot || hasReact18
const babelConfigFile = await [
'.babelrc',
@@ -265,6 +266,12 @@ export default async function getBaseWebpackConfig(
const distDir = path.join(dir, config.distDir)
/* ------ Blitz.js ------- */
const hasDbModule =
existsSync(path.join(dir, 'db/index.js')) ||
existsSync(path.join(dir, 'db/index.ts'))
/* ------ Blitz.js ------- */
// Webpack 5 can use the faster babel loader, webpack 5 has built-in caching for loaders
// For webpack 4 the old loader is used as it has external caching
const babelLoader = isWebpack5
@@ -498,7 +505,7 @@ export default async function getBaseWebpackConfig(
// Contains various versions of the Webpack SplitChunksPlugin used in different build types
const splitChunksConfigs: {
[propName: string]: webpack.Options.SplitChunksOptions
[propName: string]: webpack.Options.SplitChunksOptions | false
} = {
dev: {
cacheGroups: {
@@ -599,9 +606,9 @@ export default async function getBaseWebpackConfig(
}
// Select appropriate SplitChunksPlugin config for this build
let splitChunksConfig: webpack.Options.SplitChunksOptions
let splitChunksConfig: webpack.Options.SplitChunksOptions | false
if (dev) {
splitChunksConfig = splitChunksConfigs.dev
splitChunksConfig = isWebpack5 ? false : splitChunksConfigs.dev
} else {
splitChunksConfig = splitChunksConfigs.prodGranular
}
@@ -899,9 +906,7 @@ export default async function getBaseWebpackConfig(
entry: async () => {
return {
...(clientEntries ? clientEntries : {}),
...(isServer && doesDbModuleExist()
? { 'blitz-db': './db/index' }
: {}),
...(isServer && hasDbModule ? { 'blitz-db': './db/index' } : {}),
...entrypoints,
}
},
@@ -931,7 +936,7 @@ export default async function getBaseWebpackConfig(
: {}),
// we must set publicPath to an empty value to override the default of
// auto which doesn't work in IE11
publicPath: '',
publicPath: `${config.assetPrefix || ''}/_next/`,
path:
isServer && isWebpack5 && !dev
? path.join(outputPath, 'chunks')
@@ -950,7 +955,7 @@ export default async function getBaseWebpackConfig(
? 'static/webpack/[id].[fullhash].hot-update.js'
: 'static/webpack/[id].[hash].hot-update.js',
hotUpdateMainFilename: isWebpack5
? 'static/webpack/[fullhash].hot-update.json'
? 'static/webpack/[fullhash].[runtime].hot-update.json'
: 'static/webpack/[hash].hot-update.json',
// This saves chunks with the name given via `import()`
chunkFilename: isServer
@@ -1039,16 +1044,6 @@ export default async function getBaseWebpackConfig(
use: { loader: require.resolve('null-loader') },
},
]),
...(!config.images.disableStaticImages && isWebpack5
? [
{
test: /\.(png|svg|jpg|jpeg|gif|webp|ico|bmp)$/i,
loader: 'next-image-loader',
issuer: { not: regexLikeCss },
dependency: { not: ['url'] },
},
]
: []),
].filter(Boolean),
},
plugins: [
@@ -1111,9 +1106,7 @@ export default async function getBaseWebpackConfig(
'process.env.__NEXT_STRICT_MODE': JSON.stringify(
config.reactStrictMode
),
'process.env.__NEXT_REACT_ROOT': JSON.stringify(
config.experimental.reactRoot
),
'process.env.__NEXT_REACT_ROOT': JSON.stringify(hasReactRoot),
'process.env.__NEXT_OPTIMIZE_FONTS': JSON.stringify(
config.optimizeFonts && !dev
),
@@ -1371,12 +1364,13 @@ export default async function getBaseWebpackConfig(
type: 'filesystem',
// Includes:
// - Next.js version
// - next.config.js keys that affect compilation
// - blitz.config.js keys that affect compilation
version: `${process.env.__NEXT_VERSION}|${configVars}`,
cacheDirectory: path.join(distDir, 'cache', 'webpack'),
}
// Adds `next.config.js` as a buildDependency when custom webpack config is provided
// TODO - can we remove this?
// Adds `blitz.config.js` as a buildDependency when custom webpack config is provided
if (config.webpack && config.configFile) {
cache.buildDependencies = {
config: [config.configFile],
@@ -1479,6 +1473,30 @@ export default async function getBaseWebpackConfig(
}
}
if (!config.images.disableStaticImages && isWebpack5) {
if (!webpackConfig.module) {
webpackConfig.module = { rules: [] }
}
const hasSvg = webpackConfig.module.rules.some(
(rule) =>
'test' in rule && rule.test instanceof RegExp && rule.test.test('.svg')
)
// Exclude svg if the user already defined it in custom
// webpack config such as `@svgr/webpack` plugin or
// the `babel-plugin-inline-react-svg` plugin.
webpackConfig.module.rules.push({
test: hasSvg
? /\.(png|jpg|jpeg|gif|webp|ico|bmp)$/i
: /\.(png|svg|jpg|jpeg|gif|webp|ico|bmp)$/i,
loader: 'next-image-loader',
dependency: { not: ['url'] },
// @ts-ignore
issuer: { not: regexLikeCss },
})
}
if (
config.experimental.craCompat &&
webpackConfig.module?.rules &&

View File

@@ -1,6 +1,7 @@
import { join } from 'path'
import * as Log from '../../output/log'
import babelLoader from './babel-loader/src/index'
import { isPageFile as isPageFileFn } from '../../utils'
// increment 'p' to invalidate cache
// eslint-disable-next-line no-useless-concat
@@ -81,7 +82,7 @@ const customBabelLoader = babelLoader((babel) => {
) {
const filename = this.resourcePath
const options = Object.assign({}, cfg.options)
const isPageFile = filename.startsWith(pagesDir)
const isPageFile = isPageFileFn(filename.replace(pagesDir, ''))
if (cfg.hasFilesystemConfig()) {
for (const file of [cfg.babelrc, cfg.config]) {

View File

@@ -351,10 +351,15 @@ export function getUtils({
let defaultLocale = i18n.defaultLocale
let detectedLocale = detectLocaleCookie(req, i18n.locales)
let acceptPreferredLocale =
i18n.localeDetection !== false
? accept.language(req.headers['accept-language'], i18n.locales)
: detectedLocale
let acceptPreferredLocale
try {
acceptPreferredLocale =
i18n.localeDetection !== false
? accept.language(req.headers['accept-language'], i18n.locales)
: detectedLocale
} catch (_) {
acceptPreferredLocale = detectedLocale
}
const { host } = req.headers || {}
// remove port from host and remove port if present

View File

@@ -28,7 +28,6 @@ const eslintOptions = (args: arg.Spec) => ({
args['--report-unused-disable-directives'] || null,
cache: args['--cache'] ?? false,
cacheLocation: args['--cache-location'] || '.eslintcache',
cacheStrategy: args['--cache-strategy'] || 'metadata',
errorOnUnmatchedPattern: !Boolean(args['--no-error-on-unmatched-pattern']),
})
@@ -55,11 +54,11 @@ const nextLint: cliCommand = (argv) => {
'--fix-type': [String],
'--ignore-path': String,
'--no-ignore': Boolean,
'--quiet': Boolean,
'--no-inline-config': Boolean,
'--report-unused-disable-directives': String,
'--cache': Boolean,
'--cache-location': String,
'--cache-strategy': String,
'--no-error-on-unmatched-pattern': Boolean,
// Aliases
@@ -107,6 +106,9 @@ const nextLint: cliCommand = (argv) => {
--ignore-path path::String Specify path of ignore file
--no-ignore Disable use of ignore files and patterns
Handling warnings:
--quiet Report errors only - default: false
Inline configuration comments:
--no-inline-config Prevent comments from changing config or rules
--report-unused-disable-directives Adds reported errors for unused eslint-disable directives ("error" | "warn" | "off")
@@ -114,7 +116,6 @@ const nextLint: cliCommand = (argv) => {
Caching:
--cache Only check changed files - default: false
--cache-location path::String Path to the cache file or directory - default: .eslintcache
--cache-strategy String Strategy to use for detecting changed files - either: metadata or content - default: metadata
Miscellaneous:
--no-error-on-unmatched-pattern Prevent errors when pattern is unmatched - default: false
@@ -140,7 +141,10 @@ const nextLint: cliCommand = (argv) => {
},
[]
)
runLintCheck(baseDir, lintDirs, false, eslintOptions(args))
const reportErrorsOnly = Boolean(args['--quiet'])
runLintCheck(baseDir, lintDirs, false, eslintOptions(args), reportErrorsOnly)
.then(async (lintResults) => {
const lintOutput =
typeof lintResults === 'string' ? lintResults : lintResults?.output

View File

@@ -37,7 +37,12 @@ async function tryApplyUpdates() {
return
}
try {
const res = await fetch(`${hotUpdatePath}${curHash}.hot-update.json`)
const res = await fetch(
typeof __webpack_runtime_id__ !== 'undefined'
? // eslint-disable-next-line no-undef
`${hotUpdatePath}${curHash}.${__webpack_runtime_id__}.hot-update.json`
: `${hotUpdatePath}${curHash}.hot-update.json`
)
const jsonData = await res.json()
const curPage = page === '/' ? 'index' : page
// webpack 5 uses an array instead

View File

@@ -173,16 +173,20 @@ function handleErrors(errors) {
}
}
let startLatency = undefined
function onFastRefresh(hasUpdates) {
DevOverlay.onBuildOk()
if (hasUpdates) {
DevOverlay.onRefresh()
}
const latency = Date.now() - startLatency
console.log(`[Fast Refresh] done in ${latency}ms`)
if (self.__NEXT_HMR_LATENCY_CB) {
self.__NEXT_HMR_LATENCY_CB(latency)
if (startLatency) {
const latency = Date.now() - startLatency
console.log(`[Fast Refresh] done in ${latency}ms`)
if (self.__NEXT_HMR_LATENCY_CB) {
self.__NEXT_HMR_LATENCY_CB(latency)
}
}
}
@@ -192,8 +196,6 @@ function handleAvailableHash(hash) {
mostRecentCompilationHash = hash
}
let startLatency = undefined
// Handle messages from the server.
function processMessage(e) {
const obj = JSON.parse(e.data)

View File

@@ -348,7 +348,7 @@ export function Image({
if (process.env.NODE_ENV !== 'production') {
if (!src) {
throw new Error(
`Image is missing required "src" property. Make sure you pass "src" in props to the \`next/image\` component. Received: ${JSON.stringify(
`Image is missing required "src" property. Make sure you pass "src" in props to the \`<Image>\` component. Received: ${JSON.stringify(
{ width, height, quality }
)}`
)
@@ -360,6 +360,14 @@ export function Image({
).join(',')}.`
)
}
if (
(typeof widthInt !== 'undefined' && isNaN(widthInt)) ||
(typeof heightInt !== 'undefined' && isNaN(heightInt))
) {
throw new Error(
`Image with src "${src}" has invalid "width" or "height" property. These should be numeric values.`
)
}
if (!VALID_LOADING_VALUES.includes(loading)) {
throw new Error(
`Image with src "${src}" has invalid "loading" property. Provided "${loading}" should be one of ${VALID_LOADING_VALUES.map(
@@ -373,7 +381,7 @@ export function Image({
)
}
if (placeholder === 'blur') {
if ((widthInt || 0) * (heightInt || 0) < 1600) {
if (layout !== 'fill' && (widthInt || 0) * (heightInt || 0) < 1600) {
console.warn(
`Image with src "${src}" is smaller than 40x40. Consider removing the "placeholder='blur'" property to improve performance.`
)
@@ -569,9 +577,7 @@ export function Image({
sizes,
loader,
})}
src={src}
decoding="async"
sizes={sizes}
style={imgStyle}
className={className}
/>
@@ -676,7 +682,7 @@ function defaultLoader({
throw new Error(
`Next Image Optimization requires ${missingValues.join(
', '
)} to be provided. Make sure you pass them as props to the \`next/image\` component. Received: ${JSON.stringify(
)} to be provided. Make sure you pass them as props to the \`<Image>\` component. Received: ${JSON.stringify(
{ src, width, quality }
)}`
)
@@ -684,7 +690,7 @@ function defaultLoader({
if (src.startsWith('//')) {
throw new Error(
`Failed to parse src "${src}" on \`next/image\`, protocol-relative URL (//) must be changed to an absolute URL (http:// or https://)`
`Failed to parse src "${src}" on \`<Image>\`, protocol-relative URL (//) must be changed to an absolute URL (http:// or https://)`
)
}
@@ -695,13 +701,13 @@ function defaultLoader({
} catch (err) {
console.error(err)
throw new Error(
`Failed to parse src "${src}" on \`next/image\`, if using relative image it must start with a leading slash "/" or be an absolute URL (http:// or https://)`
`Failed to parse src "${src}" on \`<Image>\`, if using relative image it must start with a leading slash "/" or be an absolute URL (http:// or https://)`
)
}
if (!configDomains.includes(parsedSrc.hostname)) {
throw new Error(
`Invalid src prop (${src}) on \`next/image\`, hostname "${parsedSrc.hostname}" is not configured under images in your \`blitz.config.js\`\n` +
`Invalid src prop (${src}) on \`<Image>\`, hostname "${parsedSrc.hostname}" is not configured under images in your \`blitz.config.js\`\n` +
`See more info: https://nextjs.org/docs/messages/next-image-unconfigured-host`
)
}

View File

@@ -27,6 +27,12 @@ import PageLoader, { StyleSheetTuple } from './page-loader'
import measureWebVitals from './performance-relayer'
import { RouteAnnouncer } from './route-announcer'
import { createRouter, makePublicRouterInstance } from './router'
import {
AuthenticationError,
AuthorizationError,
NotFoundError,
RedirectError,
} from '../stdlib/errors'
/// <reference types="react-dom/experimental" />
@@ -96,6 +102,22 @@ if (hasBasePath(asPath)) {
asPath = delBasePath(asPath)
}
if (process.env.NODE_ENV === 'development') {
function onUnhandledError(ev: ErrorEvent) {
if (
ev.error instanceof RedirectError ||
ev.error instanceof AuthenticationError ||
ev.error instanceof AuthorizationError ||
ev.error instanceof NotFoundError
) {
// This prevents 'Uncaught error' logs in the console.
// This doesn't change how React or error boundaries handle errors
ev.preventDefault()
}
}
window.addEventListener('error', onUnhandledError)
}
if (process.env.__NEXT_I18N_SUPPORT) {
const {
normalizeLocalePath,
@@ -259,7 +281,7 @@ class Container extends React.Component<{
}
}
export const emitter: MittEmitter = mitt()
export const emitter: MittEmitter<string> = mitt()
let CachedComponent: React.ComponentType
export default async (opts: { webpackHMR?: any } = {}) => {
@@ -508,7 +530,7 @@ function renderReactElement(
const reactEl = fn(shouldHydrate ? markHydrateComplete : markRenderComplete)
if (process.env.__NEXT_REACT_ROOT) {
if (!reactRoot) {
const createRootName =
const createRootName = // blitz
typeof (ReactDOM as any).unstable_createRoot === 'function'
? 'unstable_createRoot'
: 'createRoot'

View File

@@ -7,7 +7,7 @@ export function removePathTrailingSlash(path: string): string {
/**
* Normalizes the trailing slash of a path according to the `trailingSlash` option
* in `next.config.js`.
* in `blitz.config.js`.
*/
export const normalizePathTrailingSlash = process.env.__NEXT_TRAILING_SLASH
? (path: string): string => {

View File

@@ -43,6 +43,7 @@ const urlPropertyFields = [
'isReady',
'isPreview',
'isLocaleDomain',
'domainLocales',
]
const routerEvents = [
'routeChangeStart',
@@ -51,7 +52,9 @@ const routerEvents = [
'routeChangeError',
'hashChangeStart',
'hashChangeComplete',
]
] as const
export type RouterEvent = typeof routerEvents[number]
const coreMethodFields = [
'push',
'replace',
@@ -89,7 +92,7 @@ coreMethodFields.forEach((field: string) => {
}
})
routerEvents.forEach((event: string) => {
routerEvents.forEach((event) => {
singletonRouter.ready(() => {
Router.events.on(event, (...args) => {
const eventField = `on${event.charAt(0).toUpperCase()}${event.substring(

File diff suppressed because one or more lines are too long

View File

@@ -22319,7 +22319,7 @@ module.exports = isAccessorDescriptor;
/***/ 21008:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
var isBuffer = __webpack_require__(95310);
var isBuffer = __webpack_require__(16597);
var toString = Object.prototype.toString;
/**
@@ -22437,6 +22437,34 @@ module.exports = function kindOf(val) {
};
/***/ }),
/***/ 16597:
/***/ (function(module) {
/*!
* Determine if an object is a Buffer
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
*/
// The _isBuffer check is for Safari 5-7 support, because it's missing
// Object.prototype.constructor. Remove this eventually
module.exports = function (obj) {
return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer)
}
function isBuffer (obj) {
return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj)
}
// For Node v0.10 support. Remove this eventually.
function isSlowBuffer (obj) {
return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0))
}
/***/ }),
/***/ 6284:
@@ -22505,7 +22533,7 @@ module.exports = isDataDescriptor;
/***/ 13360:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
var isBuffer = __webpack_require__(95310);
var isBuffer = __webpack_require__(16597);
var toString = Object.prototype.toString;
/**
@@ -31299,12 +31327,40 @@ module.exports = function hasValue(val) {
};
/***/ }),
/***/ 45305:
/***/ (function(module) {
/*!
* Determine if an object is a Buffer
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
*/
// The _isBuffer check is for Safari 5-7 support, because it's missing
// Object.prototype.constructor. Remove this eventually
module.exports = function (obj) {
return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer)
}
function isBuffer (obj) {
return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj)
}
// For Node v0.10 support. Remove this eventually.
function isSlowBuffer (obj) {
return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0))
}
/***/ }),
/***/ 58839:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
var isBuffer = __webpack_require__(95310);
var isBuffer = __webpack_require__(45305);
var toString = Object.prototype.toString;
/**
@@ -31552,34 +31608,6 @@ function has(obj, key) {
module.exports = isAccessorDescriptor;
/***/ }),
/***/ 95310:
/***/ (function(module) {
/*!
* Determine if an object is a Buffer
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
*/
// The _isBuffer check is for Safari 5-7 support, because it's missing
// Object.prototype.constructor. Remove this eventually
module.exports = function (obj) {
return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer)
}
function isBuffer (obj) {
return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj)
}
// For Node v0.10 support. Remove this eventually.
function isSlowBuffer (obj) {
return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0))
}
/***/ }),
/***/ 1734:
@@ -31718,12 +31746,40 @@ module.exports = function isNumber(num) {
};
/***/ }),
/***/ 51247:
/***/ (function(module) {
/*!
* Determine if an object is a Buffer
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
*/
// The _isBuffer check is for Safari 5-7 support, because it's missing
// Object.prototype.constructor. Remove this eventually
module.exports = function (obj) {
return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer)
}
function isBuffer (obj) {
return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj)
}
// For Node v0.10 support. Remove this eventually.
function isSlowBuffer (obj) {
return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0))
}
/***/ }),
/***/ 1005:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
var isBuffer = __webpack_require__(95310);
var isBuffer = __webpack_require__(51247);
var toString = Object.prototype.toString;
/**
@@ -35797,12 +35853,40 @@ module.exports = copy;
module.exports.has = has;
/***/ }),
/***/ 92541:
/***/ (function(module) {
/*!
* Determine if an object is a Buffer
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
*/
// The _isBuffer check is for Safari 5-7 support, because it's missing
// Object.prototype.constructor. Remove this eventually
module.exports = function (obj) {
return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer)
}
function isBuffer (obj) {
return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj)
}
// For Node v0.10 support. Remove this eventually.
function isSlowBuffer (obj) {
return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0))
}
/***/ }),
/***/ 73988:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
var isBuffer = __webpack_require__(95310);
var isBuffer = __webpack_require__(92541);
var toString = Object.prototype.toString;
/**
@@ -41643,12 +41727,40 @@ function assert(val, message) {
}
/***/ }),
/***/ 12633:
/***/ (function(module) {
/*!
* Determine if an object is a Buffer
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
*/
// The _isBuffer check is for Safari 5-7 support, because it's missing
// Object.prototype.constructor. Remove this eventually
module.exports = function (obj) {
return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer)
}
function isBuffer (obj) {
return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj)
}
// For Node v0.10 support. Remove this eventually.
function isSlowBuffer (obj) {
return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0))
}
/***/ }),
/***/ 31042:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
var isBuffer = __webpack_require__(95310);
var isBuffer = __webpack_require__(12633);
var toString = Object.prototype.toString;
/**
@@ -45760,12 +45872,40 @@ function filter(arr) {
}
/***/ }),
/***/ 41722:
/***/ (function(module) {
/*!
* Determine if an object is a Buffer
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
*/
// The _isBuffer check is for Safari 5-7 support, because it's missing
// Object.prototype.constructor. Remove this eventually
module.exports = function (obj) {
return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer)
}
function isBuffer (obj) {
return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj)
}
// For Node v0.10 support. Remove this eventually.
function isSlowBuffer (obj) {
return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0))
}
/***/ }),
/***/ 17728:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
var isBuffer = __webpack_require__(95310);
var isBuffer = __webpack_require__(41722);
var toString = Object.prototype.toString;
/**

View File

@@ -20,7 +20,6 @@ import {
BUILD_ID_FILE,
CLIENT_PUBLIC_FILES_PATH,
CLIENT_STATIC_FILES_PATH,
CONFIG_FILE,
EXPORT_DETAIL,
EXPORT_MARKER,
PAGES_MANIFEST,
@@ -143,7 +142,7 @@ export default async function exportApp(
return nextExportSpan.traceAsyncFn(async () => {
dir = resolve(dir)
// attempt to load global env values so they are available in next.config.js
// attempt to load global env values so they are available in blitz.config.js
nextExportSpan
.traceChild('load-dotenv')
.traceFn(() => loadEnvConfig(dir, false, Log))
@@ -308,7 +307,7 @@ export default async function exportApp(
if (typeof nextConfig.exportPathMap !== 'function') {
if (!options.silent) {
Log.info(
`No "exportPathMap" found in "${CONFIG_FILE}". Generating map from "./pages"`
`No "exportPathMap" found in "blitz.config.js". Generating map from "./pages"`
)
}
nextConfig.exportPathMap = async (defaultMap: ExportPathMap) => {
@@ -356,7 +355,7 @@ export default async function exportApp(
- Use \`blitz start\` to run a server, which includes the Image Optimization API.
- Use any provider which supports Image Optimization (like Vercel).
- Configure a third-party loader in \`blitz.config.js\`.
- Use the \`loader\` prop for \`next/image\`.
- Use the \`loader\` prop for \`blitz\`.
Read more: https://nextjs.org/docs/messages/export-image-api`
)
}

View File

@@ -0,0 +1,62 @@
// this file is conditionally added/removed to next-env.d.ts
// if the static image import handling is enabled
interface StaticImageData {
src: string
height: number
width: number
placeholder?: string
}
declare module '*.png' {
const content: StaticImageData
export default content
}
declare module '*.svg' {
/**
* Use `any` to avoid conflicts with
* `@svgr/webpack` plugin or
* `babel-plugin-inline-react-svg` plugin.
*/
const content: any
export default content
}
declare module '*.jpg' {
const content: StaticImageData
export default content
}
declare module '*.jpeg' {
const content: StaticImageData
export default content
}
declare module '*.gif' {
const content: StaticImageData
export default content
}
declare module '*.webp' {
const content: StaticImageData
export default content
}
declare module '*.ico' {
const content: StaticImageData
export default content
}
declare module '*.bmp' {
const content: StaticImageData
export default content
}

View File

@@ -28,7 +28,8 @@ async function lint(
lintDirs: string[],
eslintrcFile: string | null,
pkgJsonPath: string | null,
eslintOptions: any = null
eslintOptions: any = null,
reportErrorsOnly: boolean = false
): Promise<
| string
| null
@@ -42,7 +43,7 @@ async function lint(
const mod = await import(deps.resolved.get('eslint')!)
const { ESLint } = mod
let eslintVersion = ESLint.version
let eslintVersion = ESLint?.version
if (!ESLint) {
eslintVersion = mod?.CLIEngine?.version
@@ -59,7 +60,6 @@ async function lint(
'error'
)} - ESLint class not found. Please upgrade to ESLint version 7 or later`
}
let options: any = {
useEslintrc: true,
baseConfig: {},
@@ -85,7 +85,7 @@ async function lint(
}
}
const pagesDir = findPagesDir(baseDir)
const pagesDir = baseDir
if (nextEslintPluginIsEnabled) {
let updatedPagesDir = false
@@ -111,8 +111,9 @@ async function lint(
}
const lintStart = process.hrtime()
const results = await eslint.lintFiles(lintDirs)
let results = await eslint.lintFiles(lintDirs)
if (options.fix) await ESLint.outputFixes(results)
if (reportErrorsOnly) results = await ESLint.getErrorResults(results) // Only return errors if --quiet flag is used
const formattedResult = formatResults(baseDir, results)
const lintEnd = process.hrtime(lintStart)
@@ -142,7 +143,8 @@ export async function runLintCheck(
baseDir: string,
lintDirs: string[],
lintDuringBuild: boolean = false,
eslintOptions: any = null
eslintOptions: any = null,
reportErrorsOnly: boolean = false
): ReturnType<typeof lint> {
try {
// Find user's .eslintrc file
@@ -203,7 +205,8 @@ export async function runLintCheck(
lintDirs,
eslintrcFile,
pkgJsonPath,
eslintOptions
eslintOptions,
reportErrorsOnly
)
} catch (err) {
throw err

View File

@@ -16,7 +16,7 @@ export async function fileExists(
}
return true
} catch (err) {
if (err.code === 'ENOENT') {
if (err.code === 'ENOENT' || err.code === 'ENAMETOOLONG') {
return false
}
throw err

View File

@@ -11,7 +11,9 @@ export const existsSync = (f: string): boolean => {
}
export function findPagesDir(dir: string): string {
throw new Error('findPagesDir is deprecated in Blitz.js')
// prioritize ./pages over ./src/pages
// eslint-disable-next-line no-unreachable -- disabled in Blitz.js
let curDir = path.join(dir, 'pages')
if (existsSync(curDir)) return curDir

View File

@@ -0,0 +1,122 @@
exports.__esModule = true
exports.hasNecessaryDependencies = hasNecessaryDependencies
var _chalk = _interopRequireDefault(require('chalk'))
var _path = require('path')
var _fileExists = require('./file-exists')
var _oxfordCommaList = require('./oxford-comma-list')
var _fatalError = require('./fatal-error')
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : { default: obj }
}
const requiredTSPackages = [
{
file: 'typescript',
pkg: 'typescript',
},
{
file: '@types/react/index.d.ts',
pkg: '@types/react',
},
{
file: '@types/node/index.d.ts',
pkg: '@types/node',
},
]
const requiredLintPackages = [
{
file: 'eslint/lib/api.js',
pkg: 'eslint',
},
{
file: 'eslint-config-next',
pkg: 'eslint-config-next',
},
]
async function hasNecessaryDependencies(
baseDir,
checkTSDeps,
checkESLintDeps,
lintDuringBuild = false
) {
if (!checkTSDeps && !checkESLintDeps) {
return {
resolved: undefined,
}
}
let resolutions = new Map()
let requiredPackages = checkESLintDeps
? requiredLintPackages
: requiredTSPackages
const missingPackages = requiredPackages.filter((p) => {
try {
resolutions.set(
p.pkg,
require.resolve(p.file, {
paths: [baseDir],
})
)
return false
} catch (_) {
return true
}
})
if (missingPackages.length < 1) {
return {
resolved: resolutions,
}
}
const packagesHuman = (0, _oxfordCommaList.getOxfordCommaList)(
missingPackages.map((p) => p.pkg)
)
const packagesCli = missingPackages.map((p) => p.pkg).join(' ')
const yarnLockFile = (0, _path.join)(baseDir, 'yarn.lock')
const isYarn = await (0, _fileExists.fileExists)(yarnLockFile).catch(
() => false
)
const removalTSMsg =
'\n\n' +
_chalk.default.bold(
'If you are not trying to use TypeScript, please remove the ' +
_chalk.default.cyan('tsconfig.json') +
' file from your package root (and any TypeScript files in your pages directory).'
)
const removalLintMsg =
`\n\n` +
(lintDuringBuild
? `If you do not want to run ESLint during builds, disable it in blitz.config.js. See https://blitzjs.com/docs/eslint-config#during-builds`
: `Once installed, run ${_chalk.default.bold.cyan('next lint')} again.`)
const removalMsg = checkTSDeps ? removalTSMsg : removalLintMsg
throw new _fatalError.FatalError(
_chalk.default.bold.red(
checkTSDeps
? `It looks like you're trying to use TypeScript but do not have the required package(s) installed.`
: `To use ESLint, additional required package(s) must be installed.`
) +
'\n\n' +
_chalk.default.bold(
`Please install ${_chalk.default.bold(packagesHuman)} by running:`
) +
'\n\n' +
`\t${_chalk.default.bold.cyan(
(isYarn ? 'yarn add --dev' : 'npm install --save-dev') +
' ' +
packagesCli
)}` +
removalMsg +
'\n'
)
}
//# sourceMappingURL=has-necessary-dependencies.js.map

View File

@@ -66,7 +66,7 @@ export async function hasNecessaryDependencies(
const removalLintMsg =
`\n\n` +
(lintDuringBuild
? `If you do not want to run ESLint during builds, disable it in blitz.config.js. See https://nextjs.org/docs/api-reference/next.config.js/ignoring-eslint.`
? `If you do not want to run ESLint during builds, disable it in blitz.config.js. See https://blitzjs.com/docs/eslint-config#during-builds`
: `Once installed, run ${chalk.bold.cyan('next lint')} again.`)
const removalMsg = checkTSDeps ? removalTSMsg : removalLintMsg

View File

@@ -1,5 +1,6 @@
import { promises } from 'fs'
import { join } from 'path'
import { isPageFile, topLevelFoldersThatMayContainPages } from '../build/utils'
/**
* Recursively read directory
@@ -40,3 +41,45 @@ export async function recursiveReadDir(
return arr.sort()
}
export async function recursiveFindPages(
dir: string,
filter: RegExp,
ignore?: RegExp,
arr: string[] = [],
rootDir: string = dir
): Promise<string[]> {
let folders = await promises.readdir(dir)
if (dir === rootDir) {
folders = folders.filter((folder) =>
topLevelFoldersThatMayContainPages.includes(folder)
)
}
await Promise.all(
folders.map(async (part: string) => {
const absolutePath = join(dir, part)
if (ignore && ignore.test(part)) return
const pathStat = await promises.stat(absolutePath)
if (pathStat.isDirectory()) {
await recursiveFindPages(absolutePath, filter, ignore, arr, rootDir)
return
}
if (!filter.test(part)) {
return
}
const relativeFromRoot = absolutePath.replace(rootDir, '')
if (isPageFile(relativeFromRoot)) {
arr.push(relativeFromRoot)
return
}
})
)
return arr.sort()
}

View File

@@ -1,19 +1,22 @@
import { promises as fs } from 'fs'
import os from 'os'
import path from 'path'
import { fileExists } from '../file-exists'
export async function writeAppTypeDeclarations(baseDir: string): Promise<void> {
export async function writeAppTypeDeclarations(
baseDir: string,
imageImportsEnabled: boolean
): Promise<void> {
// Reference `next` types
const appTypeDeclarations = path.join(baseDir, 'next-env.d.ts')
const hasAppTypeDeclarations = await fileExists(appTypeDeclarations)
if (!hasAppTypeDeclarations) {
await fs.writeFile(
appTypeDeclarations,
'/// <reference types="next" />' +
os.EOL +
'/// <reference types="next/types/global" />' +
os.EOL
)
}
await fs.writeFile(
appTypeDeclarations,
'/// <reference types="next" />' +
os.EOL +
'/// <reference types="next/types/global" />' +
os.EOL +
(imageImportsEnabled
? '/// <reference types="next/image-types/global" />' + os.EOL
: '')
)
}

View File

@@ -18,6 +18,7 @@ export async function verifyTypeScriptSetup(
dir: string,
pagesDir: string,
typeCheckPreflight: boolean,
imageImportsEnabled: boolean,
cacheDir?: string
): Promise<{ result?: TypeCheckResult; version: string | null }> {
const tsConfigPath = path.join(dir, 'tsconfig.json')
@@ -42,7 +43,10 @@ export async function verifyTypeScriptSetup(
deps.resolved.get('typescript')!
)) as typeof import('typescript')
if (semver.lt(ts.version, '4.3.2')) {
if (
semver.lt(ts.version, '4.3.2') &&
!Boolean(process.env.BLITZ_TEST_ENVIRONMENT)
) {
log.warn(
`Minimum recommended TypeScript version is v4.3.2, older versions can potentially be incompatible with Blitz.js. Detected: ${ts.version}`
)
@@ -52,7 +56,7 @@ export async function verifyTypeScriptSetup(
await writeConfigurationDefaults(ts, tsConfigPath, firstTimeSetup)
// Write out the necessary `next-env.d.ts` file to correctly register
// Next.js' types:
await writeAppTypeDeclarations(dir)
await writeAppTypeDeclarations(dir, imageImportsEnabled)
let result
if (typeCheckPreflight) {

View File

@@ -15,7 +15,7 @@ export const REACT_LOADABLE_MANIFEST = 'react-loadable-manifest.json'
export const FONT_MANIFEST = 'font-manifest.json'
export const SERVER_DIRECTORY = 'server'
export const SERVERLESS_DIRECTORY = 'serverless'
export const CONFIG_FILE = 'next.config.js'
export const CONFIG_FILE = '.blitz.config.compiled.js'
export const BUILD_ID_FILE = 'BUILD_ID'
export const BLOCKED_PAGES = ['/_document', '/_app']
export const CLIENT_PUBLIC_FILES_PATH = 'public'

View File

@@ -16,13 +16,13 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
type Handler = (...evts: any[]) => void
export type MittEmitter = {
on(type: string, handler: Handler): void
off(type: string, handler: Handler): void
emit(type: string, ...evts: any[]): void
export type MittEmitter<T> = {
on(type: T, handler: Handler): void
off(type: T, handler: Handler): void
emit(type: T, ...evts: any[]): void
}
export default function mitt(): MittEmitter {
export default function mitt(): MittEmitter<string> {
const all: { [s: string]: Handler[] } = Object.create(null)
return {

View File

@@ -12,6 +12,7 @@ import {
isAssetError,
markAssetError,
} from '../../../client/route-loader'
import { RouterEvent } from '../../../client/router'
import { DomainLocales } from '../../server/config'
import { denormalizePagePath } from '../../server/denormalize-page-path'
import { normalizeLocalePath } from '../i18n/normalize-locale-path'
@@ -522,7 +523,7 @@ export default class Router implements BaseRouter {
clc: ComponentLoadCancel
pageLoader: any
_bps: BeforePopStateCallback | undefined
events: MittEmitter
events: MittEmitter<RouterEvent>
_wrapApp: (App: AppComponent) => any
isSsr: boolean
isFallback: boolean
@@ -538,7 +539,7 @@ export default class Router implements BaseRouter {
private _idx: number = 0
static events: MittEmitter = mitt()
static events: MittEmitter<RouterEvent> = mitt()
constructor(
pathname: string,
@@ -1112,14 +1113,12 @@ export default class Router implements BaseRouter {
pages
)
if (pages.includes(parsedHref.pathname)) {
const { url: newUrl, as: newAs } = prepareUrlAs(
this,
destination,
destination
)
return this.change(method, newUrl, newAs, options)
}
const { url: newUrl, as: newAs } = prepareUrlAs(
this,
destination,
destination
)
return this.change(method, newUrl, newAs, options)
}
window.location.href = destination

View File

@@ -31,6 +31,17 @@ export function matchHas(
query: Params
): false | Params {
const params: Params = {}
let initialQueryValues: string[] = []
if (typeof window === 'undefined') {
initialQueryValues = Object.values((req as any).__NEXT_INIT_QUERY)
}
if (typeof window !== 'undefined') {
initialQueryValues = Array.from(
new URLSearchParams(location.search).values()
)
}
const allMatch = has.every((hasItem) => {
let value: undefined | string
let key = hasItem.key
@@ -46,7 +57,12 @@ export function matchHas(
break
}
case 'query': {
// preserve initial encoding of query values
value = query[key!]
if (initialQueryValues.includes(value || '')) {
value = encodeURIComponent(value!)
}
break
}
case 'host': {

View File

@@ -1,6 +1,13 @@
import { existsSync, readFileSync } from 'fs'
import { build as esbuild } from 'esbuild'
import findUp from 'next/dist/compiled/find-up'
import os from 'os'
import { join } from 'path'
import { Header, Redirect, Rewrite } from '../../lib/load-custom-routes'
import { imageConfigDefault } from './image-config'
import { CONFIG_FILE } from '../lib/constants'
import { copy, remove } from 'fs-extra'
const debug = require('debug')('blitz:config')
export type DomainLocales = Array<{
http?: true
@@ -115,7 +122,7 @@ export const defaultConfig: NextConfig = {
scrollRestoration: false,
stats: false,
externalDir: false,
reactRoot: true,
reactRoot: Number(process.env.NEXT_PRIVATE_REACT_ROOT) > 0,
disableOptimizedLoading: false,
gzipSize: true,
craCompat: false,
@@ -143,3 +150,116 @@ export function normalizeConfig(phase: string, config: any) {
}
return config
}
export async function getConfigSrcPath(dir: string | null) {
if (!dir) return null
let tsPath = join(dir, 'blitz.config.ts')
let jsPath = join(dir, 'blitz.config.js')
let legacyPath = join(dir, 'next.config.js')
if (existsSync(tsPath)) {
return tsPath
} else if (existsSync(jsPath)) {
return jsPath
} else if (existsSync(legacyPath)) {
const isInternalDevelopment = __dirname.includes(
'packages/next/dist/next-server'
)
if (isInternalDevelopment || process.env.VERCEL_BUILDER) {
// We read from next.config.js that Vercel automatically adds
debug(
'Using next.config.js because isInternalDevelopment or VERCEL_BUILDER...'
)
return legacyPath
} else {
console.log('') // newline
throw new Error(
'Blitz does not support next.config.js. Please rename it to blitz.config.js'
)
}
}
if (process.env.__NEXT_TEST_MODE) {
let tsPath2 = join(dir, '..', 'blitz.config.ts')
let jsPath2 = join(dir, '..', 'blitz.config.js')
let legacyPath2 = join(dir, '..', 'next.config.js')
if (existsSync(tsPath2)) {
return tsPath2
} else if (existsSync(jsPath2)) {
return jsPath2
} else if (existsSync(legacyPath2)) {
return legacyPath2
}
}
return null
}
export function getCompiledConfigPath(dir: string) {
return join(dir, CONFIG_FILE)
}
export async function compileConfig(dir: string | null) {
debug('Starting compileConfig...')
if (!dir) {
debug('compileConfig given empty dir argument')
return
}
const srcPath = await getConfigSrcPath(dir)
debug('srcPath:', srcPath)
const compiledPath = getCompiledConfigPath(dir)
debug('compiledPath:', compiledPath)
// Remove compiled file. This is important for example when user
// had a config file but then removed it
remove(compiledPath)
if (!srcPath) {
debug('Did not find a config file')
return
}
if (readFileSync(srcPath, 'utf8').includes('tsconfig-paths/register')) {
// User is manually handling their own typescript stuff
debug(
"Config contains 'tsconfig-paths/register', so skipping build and just copying the file"
)
await copy(srcPath, compiledPath)
return
}
const pkgJsonPath = await findUp('package.json', { cwd: dir })
if (!pkgJsonPath) {
// This will happen when running blitz no inside a blitz app
debug('Unable to find package directory')
return
}
debug('Building config...')
const pkg = require(pkgJsonPath)
await esbuild({
entryPoints: [srcPath],
outfile: compiledPath,
format: 'cjs',
bundle: true,
platform: 'node',
external: [
'*.json',
'@blitzjs',
'@next',
'@zeit',
'blitz',
'next',
'webpack',
...Object.keys(require('blitz/package').dependencies),
...Object.keys(pkg?.dependencies ?? {}),
...Object.keys(pkg?.devDependencies ?? {}),
],
})
debug('Config built.')
}

View File

@@ -48,7 +48,7 @@ export async function shouldLoadWithWebpack5(
}
}
// Use webpack 5 by default in apps that do not have next.config.js
// Use webpack 5 by default in apps that do not have blitz.config.js
if (!path?.length) {
return {
enabled: true,

View File

@@ -1,14 +1,15 @@
import chalk from 'chalk'
import findUp from 'next/dist/compiled/find-up'
import { basename, extname } from 'path'
import { basename, extname, join } from 'path'
import * as Log from '../../build/output/log'
import { hasNextSupport } from '../../telemetry/ci-info'
import { CONFIG_FILE, PHASE_DEVELOPMENT_SERVER } from '../lib/constants'
import { execOnce } from '../lib/utils'
import { defaultConfig, normalizeConfig } from './config-shared'
import { compileConfig, defaultConfig, normalizeConfig } from './config-shared'
import { loadWebpackHook } from './config-utils'
import { ImageConfig, imageConfigDefault, VALID_LOADERS } from './image-config'
import { loadEnvConfig } from '@next/env'
const debug = require('debug')('blitz:config')
export { DomainLocales, NextConfig, normalizeConfig } from './config-shared'
@@ -412,6 +413,10 @@ export default async function loadConfig(
customConfig?: object | null
) {
await loadEnvConfig(dir, phase === PHASE_DEVELOPMENT_SERVER, Log)
if (!['start', 's'].includes(process.argv[2])) {
// Do not compile config for blitz start because it was already compiled during blitz build
await compileConfig(dir)
}
await loadWebpackHook(phase, dir)
if (customConfig) {
@@ -423,11 +428,20 @@ export default async function loadConfig(
// If config file was found
if (path?.length) {
const userConfigModule = require(path)
const userConfig = normalizeConfig(
let userConfig = normalizeConfig(
phase,
userConfigModule.default || userConfigModule
)
if (process.env.VERCEL_BUILDER) {
debug("Loading Vercel's next.config.js...")
const nextConfig = require(join('dir', 'next.config.js'))
debug("Vercel's next.config.js contents:", nextConfig)
for (const [key, value] of Object.entries(nextConfig)) {
userConfig[key] = value
}
}
if (Object.keys(userConfig).length === 0) {
Log.warn(
'Detected blitz.config.js, no exported configuration found. https://nextjs.org/docs/messages/empty-configuration'
@@ -461,21 +475,23 @@ export default async function loadConfig(
...userConfig,
})
} else {
const configBaseName = basename(CONFIG_FILE, extname(CONFIG_FILE))
const nonJsPath = findUp.sync(
const unsupportedPath = findUp.sync(
[
`${configBaseName}.jsx`,
`${configBaseName}.ts`,
`${configBaseName}.tsx`,
`${configBaseName}.json`,
`blitz.config.jsx`,
`blitz.config.tsx`,
`blitz.config.json`,
`next.config.jsx`,
`next.config.ts`,
`next.config.tsx`,
`next.config.json`,
],
{ cwd: dir }
)
if (nonJsPath?.length) {
if (unsupportedPath?.length) {
throw new Error(
`Configuring Blitz.js via '${basename(
nonJsPath
)}' is not supported. Please replace the file with 'blitz.config.js'.`
unsupportedPath
)}' is not supported. Please replace the file with 'blitz.config.(js|ts)'`
)
}
}

View File

@@ -122,7 +122,7 @@ export type ServerConstructor = {
*/
quiet?: boolean
/**
* Object what you would use in next.config.js - @default {}
* Object what you would use in blitz.config.js - @default {}
*/
conf?: NextConfig | null
dev?: boolean
@@ -432,11 +432,15 @@ export default class Server {
let defaultLocale = i18n.defaultLocale
let detectedLocale = detectLocaleCookie(req, i18n.locales)
let acceptPreferredLocale =
i18n.localeDetection !== false
? accept.language(req.headers['accept-language'], i18n.locales)
: detectedLocale
let acceptPreferredLocale
try {
acceptPreferredLocale =
i18n.localeDetection !== false
? accept.language(req.headers['accept-language'], i18n.locales)
: detectedLocale
} catch (_) {
acceptPreferredLocale = detectedLocale
}
const { host } = req?.headers || {}
// remove port from host if present
const hostname = host?.split(':')[0].toLowerCase()
@@ -602,7 +606,7 @@ export default class Server {
let rewrites: CustomRoutes['rewrites']
// rewrites can be stored as an array when an array is
// returned in next.config.js so massage them into
// returned in blitz.config.js so massage them into
// the expected object format
if (Array.isArray(customRoutes.rewrites)) {
rewrites = {

View File

@@ -1,7 +1,7 @@
{
"name": "next",
"version": "0.37.0",
"nextjsVersion": "11.0.0",
"version": "0.38.3-canary.1",
"nextjsVersion": "11.0.1",
"description": "The React Framework",
"main": "./dist/server/next.js",
"license": "MIT",
@@ -41,8 +41,11 @@
"router.d.ts",
"amp.js",
"amp.d.ts",
"stdlib.js",
"stdlib.d.ts",
"types/index.d.ts",
"types/global.d.ts"
"types/global.d.ts",
"image-types/global.d.ts"
],
"bin": {
"next": "./dist/bin/next"
@@ -65,10 +68,10 @@
"dependencies": {
"@babel/runtime": "7.12.5",
"@hapi/accept": "5.0.2",
"@next/env": "11.0.0",
"@next/polyfill-module": "11.0.0",
"@next/react-dev-overlay": "11.0.0",
"@next/react-refresh-utils": "11.0.0",
"@next/env": "11.0.1",
"@next/polyfill-module": "11.0.1",
"@next/react-dev-overlay": "11.0.1",
"@next/react-refresh-utils": "11.0.1",
"assert": "2.0.0",
"ast-types": "0.13.2",
"browserify-zlib": "0.2.0",
@@ -80,9 +83,12 @@
"constants-browserify": "1.0.0",
"crypto-browserify": "3.12.0",
"cssnano-simple": "2.0.0",
"debug": "4.3.1",
"domain-browser": "4.19.0",
"encoding": "0.1.13",
"esbuild": "^0.11.12",
"etag": "1.8.1",
"fs-extra": "^9.1.0",
"get-orientation": "1.1.2",
"https-browserify": "1.0.0",
"image-size": "1.0.0",
@@ -107,6 +113,7 @@
"stream-http": "3.1.1",
"string_decoder": "1.3.0",
"styled-jsx": "3.3.2",
"superjson": "1.7.2",
"timers-browserify": "2.0.12",
"tty-browserify": "0.0.1",
"use-subscription": "1.5.1",
@@ -150,7 +157,7 @@
"@babel/preset-typescript": "7.12.7",
"@babel/traverse": "^7.12.10",
"@babel/types": "7.12.12",
"@next/polyfill-nomodule": "11.0.0",
"@next/polyfill-nomodule": "11.0.1",
"@taskr/clear": "1.1.0",
"@taskr/esnext": "1.1.0",
"@taskr/watch": "1.1.0",
@@ -173,8 +180,8 @@
"@types/lru-cache": "5.1.0",
"@types/node-fetch": "2.5.8",
"@types/path-to-regexp": "1.7.0",
"@types/react": "17.0.2",
"@types/react-dom": "16.9.4",
"@types/react": "17.0.13",
"@types/react-dom": "17.0.8",
"@types/react-is": "16.7.1",
"@types/semver": "7.3.1",
"@types/send": "0.14.4",
@@ -199,7 +206,6 @@
"content-type": "1.0.4",
"cookie": "0.4.1",
"css-loader": "4.3.0",
"debug": "4.3.1",
"devalue": "2.0.1",
"escape-string-regexp": "2.0.0",
"file-loader": "6.0.0",

View File

@@ -166,7 +166,7 @@ export default class HotReloader {
this.buildId = buildId
this.dir = dir
this.middlewares = []
this.pagesDir = pagesDir
this.pagesDir = dir
this.webpackHotMiddleware = null
this.stats = null
this.serverStats = null

View File

@@ -3,7 +3,9 @@ import chalk from 'chalk'
import { warn } from '../../build/output/log'
import { promises } from 'fs'
import { denormalizePagePath } from '../../next-server/server/normalize-page-path'
import { fileExists } from '../../lib/file-exists'
// import { fileExists } from '../../lib/file-exists'
import { recursiveFindPages } from '../../lib/recursive-readdir'
import { buildPageExtensionRegex } from '../../build/utils'
async function isTrueCasePagePath(pagePath: string, pagesDir: string) {
const pageSegments = normalize(pagePath).split(pathSeparator).filter(Boolean)
@@ -22,27 +24,60 @@ export async function findPageFile(
normalizedPagePath: string,
pageExtensions: string[]
): Promise<string | null> {
const foundPagePaths: string[] = []
// console.log('[findPageFile]', { rootDir, normalizedPagePath })
const page = denormalizePagePath(normalizedPagePath)
for (const extension of pageExtensions) {
if (!normalizedPagePath.endsWith('/index')) {
const relativePagePath = `${page}.${extension}`
const pagePath = join(rootDir, relativePagePath)
const allPages = await recursiveFindPages(
rootDir,
buildPageExtensionRegex(pageExtensions)
)
// console.log('allPages', allPages)
if (await fileExists(pagePath)) {
foundPagePaths.push(relativePagePath)
}
}
const relativePagePathWithIndex = join(page, `index.${extension}`)
const pagePathWithIndex = join(rootDir, relativePagePathWithIndex)
if (await fileExists(pagePathWithIndex)) {
foundPagePaths.push(relativePagePathWithIndex)
}
let prefix: string
if (normalizedPagePath.startsWith('/api/')) {
prefix = ''
} else {
prefix = '/pages'
}
let nameMatch: string
if (page === '/') {
nameMatch = normalizedPagePath
} else if (page.endsWith('/index')) {
nameMatch = `${page}/index`
} else {
nameMatch = `(${page}|${page}/index)`
}
nameMatch = nameMatch.replace(/[[\]\\]/g, '\\$&')
const foundPagePaths = allPages.filter((path) =>
path.match(
new RegExp(`${prefix}${nameMatch}\\.(?:${pageExtensions.join('|')})$`)
)
)
// console.log(
// new RegExp(`${prefix}${nameMatch}\\.(?:${pageExtensions.join('|')})$`)
// )
// console.log('FOUND', foundPagePaths)
// for (const extension of pageExtensions) {
// if (!normalizedPagePath.endsWith('/index')) {
// const relativePagePath = `${page}.${extension}`
// const pagePath = join(rootDir, relativePagePath)
//
// if (await fileExists(pagePath)) {
// foundPagePaths.push(relativePagePath)
// }
// }
//
// const relativePagePathWithIndex = join(page, `index.${extension}`)
// const pagePathWithIndex = join(rootDir, relativePagePathWithIndex)
// if (await fileExists(pagePathWithIndex)) {
// foundPagePaths.push(relativePagePathWithIndex)
// }
// }
if (foundPagePaths.length < 1) {
return null
}

View File

@@ -1,5 +1,5 @@
import fs from 'fs'
import path from 'path'
import findUp from 'next/dist/compiled/find-up'
import { dirname } from 'path'
export function printAndExit(message: string, code = 1) {
if (code === 0) {
@@ -16,16 +16,14 @@ export function getNodeOptionsWithoutInspect() {
return (process.env.NODE_OPTIONS || '').replace(NODE_INSPECT_RE, '')
}
export function getProjectRoot() {
return path.dirname(getConfigSrcPath())
}
export async function getProjectRoot(dir: string) {
const pkgJsonPath = await findUp('package.json', { cwd: dir })
export function getConfigSrcPath() {
const tsPath = path.resolve(path.join(process.cwd(), 'blitz.config.ts'))
if (fs.existsSync(tsPath)) {
return tsPath
} else {
const jsPath = path.resolve(path.join(process.cwd(), 'blitz.config.js'))
return jsPath
if (!pkgJsonPath) {
throw new Error(
'Unable to find project root by looking for your package.json'
)
}
return dirname(pkgJsonPath)
}

View File

@@ -12,7 +12,6 @@ import { ampValidation } from '../build/output/index'
import * as Log from '../build/output/log'
import { PUBLIC_DIR_MIDDLEWARE_CONFLICT } from '../lib/constants'
import { fileExists } from '../lib/file-exists'
import { findPagesDir } from '../lib/find-pages-dir'
import loadCustomRoutes, { CustomRoutes } from '../lib/load-custom-routes'
import { verifyTypeScriptSetup } from '../lib/verifyTypeScriptSetup'
import {
@@ -39,6 +38,12 @@ import { findPageFile } from './lib/find-page-file'
import { getNodeOptionsWithoutInspect } from './lib/utils'
import { withCoalescedInvoke } from '../lib/coalesced-function'
import { NextConfig } from '../next-server/server/config'
import {
buildPageExtensionRegex,
convertPageFilePathToRoutePath,
isPageFile,
topLevelFoldersThatMayContainPages,
} from '../build/utils'
if (typeof React.Suspense === 'undefined') {
throw new Error(
@@ -107,7 +112,7 @@ export default class DevServer extends Server {
)
}
this.isCustomServer = !options.isNextDevCommand
this.pagesDir = findPagesDir(this.dir)
this.pagesDir = this.dir
this.staticPathsWorker = new Worker(
require.resolve('./static-paths-worker'),
{
@@ -187,8 +192,8 @@ export default class DevServer extends Server {
return
}
const regexPageExtension = new RegExp(
`\\.+(?:${this.nextConfig.pageExtensions.join('|')})$`
const regexPageExtension = buildPageExtensionRegex(
this.nextConfig.pageExtensions
)
let resolved = false
@@ -208,18 +213,31 @@ export default class DevServer extends Server {
})
let wp = (this.webpackWatcher = new Watchpack())
wp.watch([], [pagesDir!], 0)
wp.watch(
[],
topLevelFoldersThatMayContainPages.map((dir) =>
pathJoin(pagesDir!, dir)
),
0
)
wp.on('aggregated', () => {
const routedPages = []
const knownFiles = wp.getTimeInfoEntries()
for (const [fileName, { accuracy }] of knownFiles) {
if (accuracy === undefined || !regexPageExtension.test(fileName)) {
for (const [filePath, { accuracy }] of knownFiles) {
const relativePath = '/' + relative(pagesDir!, filePath)
if (
accuracy === undefined ||
!isPageFile(relativePath) ||
!regexPageExtension.test(filePath)
) {
continue
}
let pageName =
'/' + relative(pagesDir!, fileName).replace(/\\+/g, '/')
let pageName = relativePath.replace(/\\+/g, '/')
pageName = convertPageFilePathToRoutePath(pageName)
pageName = pageName.replace(regexPageExtension, '')
pageName = pageName.replace(/\/index$/, '') || '/'
@@ -275,7 +293,12 @@ export default class DevServer extends Server {
}
async prepare(): Promise<void> {
await verifyTypeScriptSetup(this.dir, this.pagesDir!, false)
await verifyTypeScriptSetup(
this.dir,
this.pagesDir!,
false,
!this.nextConfig.images.disableStaticImages
)
this.customRoutes = await loadCustomRoutes(this.nextConfig)

View File

@@ -11,6 +11,7 @@ import {
import { pageNotFoundError } from '../next-server/server/require'
import { findPageFile } from './lib/find-page-file'
import getRouteFromEntrypoint from '../next-server/server/get-route-from-entrypoint'
import { convertPageFilePathToRoutePath } from '../build/utils'
export const ADDED = Symbol('added')
export const BUILDING = Symbol('building')
@@ -158,7 +159,7 @@ export default function onDemandEntryHandler(
throw pageNotFoundError(normalizedPagePath)
}
let pageUrl = pagePath.replace(/\\/g, '/')
let pageUrl = convertPageFilePathToRoutePath(pagePath.replace(/\\/g, '/'))
pageUrl = `${pageUrl[0] !== '/' ? '/' : ''}${pageUrl
.replace(new RegExp(`\\.+(?:${pageExtensions.join('|')})$`), '')

2
nextjs/packages/next/stdlib.d.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
export * from './dist/stdlib/index'
export { default } from './dist/stdlib/index'

View File

@@ -0,0 +1 @@
module.exports = require('./dist/stdlib/index')

View File

@@ -1,15 +1,15 @@
import SuperJson from "superjson"
import type {UrlObject} from "url"
import SuperJson from 'superjson'
import type { UrlObject } from 'url'
const errorProps = ["name", "message", "code", "statusCode", "meta"]
const errorProps = ['name', 'message', 'code', 'statusCode', 'meta']
if (process.env.JEST_WORKER_ID === undefined) {
SuperJson.allowErrorProps(...errorProps)
}
export class AuthenticationError extends Error {
name = "AuthenticationError"
name = 'AuthenticationError'
statusCode = 401
constructor(message = "You must be logged in to access this") {
constructor(message = 'You must be logged in to access this') {
super(message)
}
get _clearStack() {
@@ -18,13 +18,13 @@ export class AuthenticationError extends Error {
}
if (process.env.JEST_WORKER_ID === undefined) {
SuperJson.registerClass(AuthenticationError, {
identifier: "BlitzAuthenticationError",
identifier: 'BlitzAuthenticationError',
allowProps: errorProps,
})
}
export class CSRFTokenMismatchError extends Error {
name = "CSRFTokenMismatchError"
name = 'CSRFTokenMismatchError'
statusCode = 401
get _clearStack() {
return true
@@ -32,15 +32,15 @@ export class CSRFTokenMismatchError extends Error {
}
if (process.env.JEST_WORKER_ID === undefined) {
SuperJson.registerClass(CSRFTokenMismatchError, {
identifier: "BlitzCSRFTokenMismatchError",
identifier: 'BlitzCSRFTokenMismatchError',
allowProps: errorProps,
})
}
export class AuthorizationError extends Error {
name = "AuthorizationError"
name = 'AuthorizationError'
statusCode = 403
constructor(message = "You are not authorized to access this") {
constructor(message = 'You are not authorized to access this') {
super(message)
}
get _clearStack() {
@@ -49,15 +49,15 @@ export class AuthorizationError extends Error {
}
if (process.env.JEST_WORKER_ID === undefined) {
SuperJson.registerClass(AuthorizationError, {
identifier: "BlitzAuthorizationError",
identifier: 'BlitzAuthorizationError',
allowProps: errorProps,
})
}
export class NotFoundError extends Error {
name = "NotFoundError"
name = 'NotFoundError'
statusCode = 404
constructor(message = "This could not be found") {
constructor(message = 'This could not be found') {
super(message)
}
get _clearStack() {
@@ -65,29 +65,32 @@ export class NotFoundError extends Error {
}
}
if (process.env.JEST_WORKER_ID === undefined) {
SuperJson.registerClass(NotFoundError, {identifier: "BlitzNotFoundError", allowProps: errorProps})
SuperJson.registerClass(NotFoundError, {
identifier: 'BlitzNotFoundError',
allowProps: errorProps,
})
}
export class PaginationArgumentError extends Error {
name = "PaginationArgumentError"
name = 'PaginationArgumentError'
statusCode = 422
constructor(message = "The pagination arguments are invalid") {
constructor(message = 'The pagination arguments are invalid') {
super(message)
}
}
if (process.env.JEST_WORKER_ID === undefined) {
SuperJson.registerClass(PaginationArgumentError, {
identifier: "BlitzPaginationArgumentError",
identifier: 'BlitzPaginationArgumentError',
allowProps: errorProps,
})
}
export class RedirectError extends Error {
name = "RedirectError"
name = 'RedirectError'
statusCode = 302
url: UrlObject | string
constructor(url: UrlObject | string) {
super(typeof url === "object" ? url.href! : url)
super(typeof url === 'object' ? url.href! : url)
this.url = url
}
get _clearStack() {
@@ -95,5 +98,8 @@ export class RedirectError extends Error {
}
}
if (process.env.JEST_WORKER_ID === undefined) {
SuperJson.registerClass(NotFoundError, {identifier: "BlitzRedirectError", allowProps: errorProps})
SuperJson.registerClass(NotFoundError, {
identifier: 'BlitzRedirectError',
allowProps: errorProps,
})
}

View File

@@ -0,0 +1 @@
export * from './errors'

View File

@@ -807,6 +807,7 @@ export async function compile(task, opts) {
'pages',
'lib',
'client',
'stdlib',
'telemetry',
'nextserver',
'nextserver_wasm',
@@ -866,6 +867,14 @@ export async function client(task, opts) {
notify('Compiled client files')
}
export async function stdlib(task, opts) {
await task
.source(opts.src || 'stdlib/**/*.+(js|ts|tsx)')
.babel('stdlib', { dev: opts.dev })
.target('dist/stdlib')
notify('Compiled stdlib files')
}
// export is a reserved keyword for functions
export async function nextbuildstatic(task, opts) {
await task
@@ -922,6 +931,7 @@ export default async function (task) {
await task.watch('build/**/*.+(js|ts|tsx)', 'nextbuild', opts)
await task.watch('export/**/*.+(js|ts|tsx)', 'nextbuildstatic', opts)
await task.watch('client/**/*.+(js|ts|tsx)', 'client', opts)
await task.watch('stdlib/**/*.+(js|ts|tsx)', 'stdlib', opts)
await task.watch('lib/**/*.+(js|ts|tsx)', 'lib', opts)
await task.watch('cli/**/*.+(js|ts|tsx)', 'cli', opts)
await task.watch('telemetry/**/*.+(js|ts|tsx)', 'telemetry', opts)

Some files were not shown because too many files have changed in this diff Show More