Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

fix(next/image): render valid html according to W3C #33825

Merged
merged 11 commits into from Feb 1, 2022
Merged

fix(next/image): render valid html according to W3C #33825

merged 11 commits into from Feb 1, 2022

Conversation

theoludwig
Copy link
Contributor

@theoludwig theoludwig commented Jan 31, 2022

Bug

await waitFor(1000)
expect(await browser.hasElementByCssSelector('img')).toBeTruthy()
const url = await browser.url()
const result = await validateHTML({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could add this to the existing image-component test suite here instead and ensure the different layouts all validate correctly

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, done! 👍

To keep things simple, I still added a new page /valid-html-w3c in the default folder.

package.json Outdated
@@ -112,6 +113,7 @@
"get-port": "5.1.1",
"glob": "7.1.6",
"gzip-size": "5.1.1",
"html-validator": "5",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason this isn't using the latest version, 6?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, v6 dropped support for Node.js v12 (ref: zrrrzzt/html-validator@c3a11fa), hence failing the test using Node.js v12.
But Next.js support Node.js >= 12.22.0.

But yes instead to use 5, we could use 5.1.18. 👍

Co-authored-by: Steven <steven@ceriously.com>
@ijjk

This comment has been minimized.

@ijjk

This comment has been minimized.

@theoludwig
Copy link
Contributor Author

There are a few failing tests, even if this PR fixes the W3C issue, it breaks a lot of things!

Instead, to do the fix by adding + instead of space, I reverted PR #33218, I think it is the easiest fix.
I think that using base64 encoding is still fine, now that we have the integration test to avoid regression again, it might be safer to do #33218, if it is still really wanted but that would probably be in another PR.

Could you rerun the GitHub Actions to see if indeed reverting #33218 fixes the issue? 😄

it('should be valid W3C HTML', async () => {
let browser
try {
browser = await webdriver(appPort, '/valid-html-w3c')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets loop through every page here to ensure all usages of the image component are valid HTML

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will try but that requires a lot of changes to these pages because a lot of them are not valid W3C because of all kinds of errors like duplicated IDs etc. And I feel like it's unrelated to this PR.

Testing only with the /valid-html-w3c page keeps things simple and only test what is really needed.
Will keep you updated! 👍

@styfle
Copy link
Member

styfle commented Jan 31, 2022

You should be able to run the tests locally with yarn testheadless test/integration/image-optimizer/test/index.test.js

@ijjk

This comment has been minimized.

@theoludwig
Copy link
Contributor Author

You should be able to run the tests locally with yarn testheadless test/integration/image-optimizer/test/index.test.js

Thanks for the tip! I was using this command: node './node_modules/.bin/jest' './test/integration/image-component/default/test/index.test.js' -t 'Image Component Tests' but I had issues with errors like that: connect ECONNREFUSED 127.0.0.1:42635.

It seems like all the tests pass except on the Azure side (no idea why it's completely unrelated tests that fail).

@styfle
Copy link
Member

styfle commented Jan 31, 2022

Lets make sure to run validation on all pages. You can update the test to do fs.readdir() to find all the pages in that test fixture.

@theoludwig
Copy link
Contributor Author

theoludwig commented Jan 31, 2022

Yes, here is what I did:

it('should be valid W3C HTML', async () => {
  let browser
  const pages = readdirSync(join(appDir, 'pages'))
    .filter((page) => {
      return page !== '_document.js' && page !== '_app.js'
    })
    .map((page) => {
      return `/${page.replace(/\.js$/, '')}`
    })
  for (const page of pages) {
    console.log(`Validating ${page}`)
    try {
      browser = await webdriver(appPort, page)
      await waitFor(1000)
      expect(await browser.hasElementByCssSelector('img')).toBeTruthy()
      const url = await browser.url()
      const result = await validateHTML({
        url,
        format: 'json',
        isLocal: true,
      })
      expect(result.messages).toEqual([])
    } finally {
      if (browser) {
        await browser.close()
      }
    }
  }
})

It is working, but there are so many W3C errors (whereas /valid-html-w3c has no error)...
A few examples include:

  • Attribute “imagesrcset” not allowed on element “link” at this point.
  • Element “link” is missing one or more of the following attributes: “href”, “resource”.
  • An “img” element must have an “alt” attribute, except under certain conditions. For details, consult guidance on providing text alternatives for images.
  • Duplicate ID “blurry-placeholder-with-lazy”.

So it makes sense to only test that we render valid HTML when the user correctly use next/image.
For example: /missing-src is of course not valid HTML because the user didn't specified src.

styfle
styfle previously approved these changes Jan 31, 2022
Copy link
Member

@styfle styfle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, we can add it in a follow up PR. Thanks!

@ijjk

This comment has been minimized.

@styfle styfle requested a review from sokra January 31, 2022 22:50
Copy link
Member

@styfle styfle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I encoded space as %20 now it passes validation 👍

@ijjk
Copy link
Member

ijjk commented Jan 31, 2022

Stats from current PR

Default Build (Decrease detected ✓)
General Overall decrease ✓
vercel/next.js canary Divlo/next.js fix/next-image-render-valid-html-w3c Change
buildDuration 14.6s 14.7s ⚠️ +102ms
buildDurationCached 3.7s 3.7s -36ms
nodeModulesSize 358 MB 358 MB -95 B
Page Load Tests Overall decrease ⚠️
vercel/next.js canary Divlo/next.js fix/next-image-render-valid-html-w3c Change
/ failed reqs 0 0
/ total time (seconds) 3.439 3.439
/ avg req/sec 727.06 726.95 ⚠️ -0.11
/error-in-render failed reqs 0 0
/error-in-render total time (seconds) 1.561 1.59 ⚠️ +0.03
/error-in-render avg req/sec 1601.05 1572.09 ⚠️ -28.96
Client Bundles (main, webpack, commons)
vercel/next.js canary Divlo/next.js fix/next-image-render-valid-html-w3c Change
450.HASH.js gzip 179 B 179 B
framework-HASH.js gzip 42.2 kB 42.2 kB
main-HASH.js gzip 27.2 kB 27.2 kB
webpack-HASH.js gzip 1.44 kB 1.44 kB
Overall change 71 kB 71 kB
Legacy Client Bundles (polyfills)
vercel/next.js canary Divlo/next.js fix/next-image-render-valid-html-w3c Change
polyfills-HASH.js gzip 31 kB 31 kB
Overall change 31 kB 31 kB
Client Pages Overall increase ⚠️
vercel/next.js canary Divlo/next.js fix/next-image-render-valid-html-w3c Change
_app-HASH.js gzip 1.37 kB 1.37 kB
_error-HASH.js gzip 194 B 194 B
amp-HASH.js gzip 312 B 312 B
css-HASH.js gzip 326 B 326 B
dynamic-HASH.js gzip 2.37 kB 2.37 kB
head-HASH.js gzip 350 B 350 B
hooks-HASH.js gzip 919 B 919 B
image-HASH.js gzip 4.93 kB 4.94 kB ⚠️ +4 B
index-HASH.js gzip 263 B 263 B
link-HASH.js gzip 2.19 kB 2.19 kB
routerDirect..HASH.js gzip 321 B 321 B
script-HASH.js gzip 383 B 383 B
withRouter-HASH.js gzip 318 B 318 B
85e02e95b279..7e3.css gzip 107 B 107 B
Overall change 14.3 kB 14.4 kB ⚠️ +4 B
Client Build Manifests Overall decrease ✓
vercel/next.js canary Divlo/next.js fix/next-image-render-valid-html-w3c Change
_buildManifest.js gzip 460 B 459 B -1 B
Overall change 460 B 459 B -1 B
Rendered Page Sizes
vercel/next.js canary Divlo/next.js fix/next-image-render-valid-html-w3c Change
index.html gzip 530 B 530 B
link.html gzip 545 B 545 B
withRouter.html gzip 526 B 526 B
Overall change 1.6 kB 1.6 kB

Diffs

Diff for _buildManifest.js
@@ -12,7 +12,7 @@ self.__BUILD_MANIFEST = {
   ],
   "/head": ["static\u002Fchunks\u002Fpages\u002Fhead-7100d3b2a548f0e4.js"],
   "/hooks": ["static\u002Fchunks\u002Fpages\u002Fhooks-538d621a0e670391.js"],
-  "/image": ["static\u002Fchunks\u002Fpages\u002Fimage-2477effd702d0bcc.js"],
+  "/image": ["static\u002Fchunks\u002Fpages\u002Fimage-53463827ccaef972.js"],
   "/link": ["static\u002Fchunks\u002Fpages\u002Flink-f0a2c3bb0706d8b2.js"],
   "/routerDirect": [
     "static\u002Fchunks\u002Fpages\u002FrouterDirect-76232dd6bc335a24.js"
Diff for image-HASH.js
@@ -662,9 +662,8 @@
             wrapperStyle.maxWidth = "100%";
             hasSizer = true;
             sizerStyle.maxWidth = "100%";
-            // url encoded svg is a little bit shorten than base64 encoding
-            sizerSvgUrl = "data:image/svg+xml,%3csvg xmlns=%27http://www.w3.org/2000/svg%27 version=%271.1%27 width=%27"
-              .concat(widthInt, "%27 height=%27")
+            sizerSvgUrl = "data:image/svg+xml,%3csvg%20xmlns=%27http://www.w3.org/2000/svg%27%20version=%271.1%27%20width=%27"
+              .concat(widthInt, "%27%20height=%27")
               .concat(heightInt, "%27/%3e");
           } else if (layout === "fixed") {
             // <Image src="i.png" width="100" height="100" layout="fixed" />

Default Build with SWC (Decrease detected ✓)
General Overall decrease ✓
vercel/next.js canary Divlo/next.js fix/next-image-render-valid-html-w3c Change
buildDuration 18.1s 18.2s ⚠️ +139ms
buildDurationCached 3.7s 3.7s -34ms
nodeModulesSize 358 MB 358 MB -95 B
Page Load Tests Overall decrease ⚠️
vercel/next.js canary Divlo/next.js fix/next-image-render-valid-html-w3c Change
/ failed reqs 0 0
/ total time (seconds) 3.443 3.394 -0.05
/ avg req/sec 726.13 736.52 +10.39
/error-in-render failed reqs 0 0
/error-in-render total time (seconds) 1.565 1.577 ⚠️ +0.01
/error-in-render avg req/sec 1597.64 1585.09 ⚠️ -12.55
Client Bundles (main, webpack, commons)
vercel/next.js canary Divlo/next.js fix/next-image-render-valid-html-w3c Change
450.HASH.js gzip 179 B 179 B
framework-HASH.js gzip 42.3 kB 42.3 kB
main-HASH.js gzip 27.3 kB 27.3 kB
webpack-HASH.js gzip 1.44 kB 1.44 kB
Overall change 71.3 kB 71.3 kB
Legacy Client Bundles (polyfills)
vercel/next.js canary Divlo/next.js fix/next-image-render-valid-html-w3c Change
polyfills-HASH.js gzip 31 kB 31 kB
Overall change 31 kB 31 kB
Client Pages Overall increase ⚠️
vercel/next.js canary Divlo/next.js fix/next-image-render-valid-html-w3c Change
_app-HASH.js gzip 1.35 kB 1.35 kB
_error-HASH.js gzip 180 B 180 B
amp-HASH.js gzip 305 B 305 B
css-HASH.js gzip 321 B 321 B
dynamic-HASH.js gzip 2.36 kB 2.36 kB
head-HASH.js gzip 342 B 342 B
hooks-HASH.js gzip 911 B 911 B
image-HASH.js gzip 4.97 kB 4.98 kB ⚠️ +5 B
index-HASH.js gzip 256 B 256 B
link-HASH.js gzip 2.21 kB 2.21 kB
routerDirect..HASH.js gzip 314 B 314 B
script-HASH.js gzip 375 B 375 B
withRouter-HASH.js gzip 309 B 309 B
85e02e95b279..7e3.css gzip 107 B 107 B
Overall change 14.3 kB 14.3 kB ⚠️ +5 B
Client Build Manifests
vercel/next.js canary Divlo/next.js fix/next-image-render-valid-html-w3c Change
_buildManifest.js gzip 458 B 458 B
Overall change 458 B 458 B
Rendered Page Sizes
vercel/next.js canary Divlo/next.js fix/next-image-render-valid-html-w3c Change
index.html gzip 531 B 531 B
link.html gzip 544 B 544 B
withRouter.html gzip 526 B 526 B
Overall change 1.6 kB 1.6 kB

Diffs

Diff for _buildManifest.js
@@ -12,7 +12,7 @@ self.__BUILD_MANIFEST = {
   ],
   "/head": ["static\u002Fchunks\u002Fpages\u002Fhead-7100d3b2a548f0e4.js"],
   "/hooks": ["static\u002Fchunks\u002Fpages\u002Fhooks-538d621a0e670391.js"],
-  "/image": ["static\u002Fchunks\u002Fpages\u002Fimage-2477effd702d0bcc.js"],
+  "/image": ["static\u002Fchunks\u002Fpages\u002Fimage-53463827ccaef972.js"],
   "/link": ["static\u002Fchunks\u002Fpages\u002Flink-f0a2c3bb0706d8b2.js"],
   "/routerDirect": [
     "static\u002Fchunks\u002Fpages\u002FrouterDirect-76232dd6bc335a24.js"
Diff for image-HASH.js
@@ -662,9 +662,8 @@
             wrapperStyle.maxWidth = "100%";
             hasSizer = true;
             sizerStyle.maxWidth = "100%";
-            // url encoded svg is a little bit shorten than base64 encoding
-            sizerSvgUrl = "data:image/svg+xml,%3csvg xmlns=%27http://www.w3.org/2000/svg%27 version=%271.1%27 width=%27"
-              .concat(widthInt, "%27 height=%27")
+            sizerSvgUrl = "data:image/svg+xml,%3csvg%20xmlns=%27http://www.w3.org/2000/svg%27%20version=%271.1%27%20width=%27"
+              .concat(widthInt, "%27%20height=%27")
               .concat(heightInt, "%27/%3e");
           } else if (layout === "fixed") {
             // <Image src="i.png" width="100" height="100" layout="fixed" />
Commit: 2a03501

@styfle styfle merged commit e0095fa into vercel:canary Feb 1, 2022
@theoludwig theoludwig deleted the fix/next-image-render-valid-html-w3c branch February 1, 2022 06:13
@theoludwig
Copy link
Contributor Author

I encoded space as %20 now it passes validation +1

Great, good solution! 👍 (better than reverting). Thanks for your help. @styfle

natew pushed a commit to natew/next.js that referenced this pull request Feb 16, 2022
## Bug

- [x] Fixes vercel#33809
- [x] Related to vercel#33218
- [x] Integration tests added: Usage of [html-validator](https://www.npmjs.com/package/html-validator) to validate the HTML.
- [x] Errors have helpful link attached, see `contributing.md` (N/A)
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 3, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

next/image produces invalid HTML according to W3C (again)
3 participants