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

Storybook fonts still failing to load from within Docker as of version 0.32 #471

Closed
p3k opened this issue Jul 27, 2023 · 3 comments · Fixed by #472
Closed

Storybook fonts still failing to load from within Docker as of version 0.32 #471

p3k opened this issue Jul 27, 2023 · 3 comments · Fixed by #472

Comments

@p3k
Copy link

p3k commented Jul 27, 2023

I am aware of #446 – when running Loki on the host the issue was reproducible with 0.31.x and got remedied with an upgrade to 0.32.

Running Loki with Chrome app from within a Docker context, however, the issue resurfaces again even with 0.32:

❯ docker exec -it -u root dev-image bash
root@dev-image:~# yarn loki --requireReference --reactUri file:./client/build/storybook --chromeFlags="--headless --no-sandbox"
loki test v0.32.0
(node:9173) NOTE: We are formalizing our plans to enter AWS SDK for JavaScript (v2) into maintenance mode in 2023.

Please migrate your code to use AWS SDK for JavaScript (v3).
For more information, check the migration guide at https://a.co/7PzMCcy
(Use `node --trace-warnings ...` to show where the warning was created)
 FAIL  chrome.app
       Fetching stories
       8 requests failed to load; file:///home/dev/portal/client/build/storybook/sb-common-assets/nunito-sans-regular.woff2, file:///home/dev/portal/client/build/storybook/sb-common-assets/nunito-sans-italic.woff2, 
       file:///home/dev/portal/client/build/storybook/sb-common-assets/nunito-sans-bold.woff2, file:///home/dev/portal/client/build/storybook/sb-common-assets/nunito-sans-bold-italic.woff2, 
       file:///home/dev/portal/client/build/storybook/sb-preview/runtime.js, file:///home/dev/portal/client/build/storybook/runtime~main.a3289e97.iframe.bundle.js, file:///home/dev/portal/client/build/storybook/9504.0b91993e.iframe.bundle.js, 
       file:///home/dev/portal/client/build/storybook/main.2e79e3e5.iframe.bundle.js
Some visual tests failed to run

Any suggestions?

Config

{
	"configurations": {
		"chrome.laptop": {
			"target": "chrome.app",
			"width": 1366,
			"height": 768,
			"deviceScaleFactor": 1,
			"mobile": false
		},
		"chrome.iphone7": {
			"target": "chrome.app",
			"preset": "iPhone 7"
		}
	}
}
@p3k p3k changed the title Storybook fonts still failing to load from within Docker-in-Docker as of version 0.32 Storybook fonts still failing to load from within Docker as of version 0.32 Jul 27, 2023
@gidztech
Copy link
Contributor

I'm running into this issue in CI too with Storybook 7. I've not got any solution/workaround at the moment.

@gidztech
Copy link
Contributor

gidztech commented Aug 4, 2023

I have a PR open now to resolve the issue. The static file server needed to be implemented for the app target just like the Docker one. #472

@gidztech
Copy link
Contributor

gidztech commented Aug 21, 2023

I came up with a hacky workaround while I wait for a fix to be approved/released. I originally patched Loki with my branch version, but building from .tgz files was very slow.

The preview for Storybook references the static assets (fonts, stylesheet and scripts) with ./ prefix, which causes issues with Loki's current use of file:// protocol. In addition, it loads scripts as ES modules, which also is problematic under the current setup. This is configured via a preview template, but Storybook allows you to customize it using the previewMainTemplate property in .storybook/main.ts.

I copied template.ejs into my .storybook folder and applied the following changes:

  1. Removed the ./ prefix to the static assets
  2. Removed crossorigin from the fonts
  3. Replaced the ES imports with injected script tags
  4. Referenced a different preview runtime script (see more later)
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title><%= htmlWebpackPlugin.options.title || 'Storybook'%></title>

    <% if (htmlWebpackPlugin.files.favicon) { %>
    <link rel="shortcut icon" href="<%= htmlWebpackPlugin.files.favicon%>" />
    <% } %>

    <meta name="viewport" content="width=device-width, initial-scale=1" />

    <link rel="prefetch" href="sb-common-assets/nunito-sans-regular.woff2" as="font" type="font/woff2" />
    <link rel="prefetch" href="sb-common-assets/nunito-sans-italic.woff2" as="font" type="font/woff2" />
    <link rel="prefetch" href="sb-common-assets/nunito-sans-bold.woff2" as="font" type="font/woff2" />
    <link rel="prefetch" href="sb-common-assets/nunito-sans-bold-italic.woff2" as="font" type="font/woff2" />
    <link rel="stylesheet" href="sb-common-assets/fonts.css" />

    <% if (typeof headHtmlSnippet !== 'undefined') { %> <%= headHtmlSnippet %> <% } %> <%
    htmlWebpackPlugin.files.css.forEach(file => { %>
    <link href="<%= file %>" rel="stylesheet" />
    <% }); %>

    <style>
      #storybook-root[hidden],
      #storybook-docs[hidden] {
        display: none !important;
      }
    </style>
  </head>
  <body>
    <% if (typeof bodyHtmlSnippet !== 'undefined') { %> <%= bodyHtmlSnippet %> <% } %>

    <div id="storybook-root"></div>
    <div id="storybook-docs"></div>

    <% if (typeof globals !== 'undefined' && Object.keys(globals).length) { %>
    <script>
      <% for (var varName in globals) { %>
          <% if (globals[varName] != undefined) { %>
            window['<%=varName%>'] = <%= JSON.stringify(globals[varName]) %>;
          <% } %>
      <% } %>
    </script>
    <% } %>

    <script>
      function insertScript(src) {
        const script = document.createElement('script');
        script.src = src;
        document.body.append(script);
      }

      insertScript('sb-preview/runtime_browser.js');

      <% htmlWebpackPlugin.files.js.forEach(file => { %>
        insertScript('<%= file %>');
      <% }); %>
    </script>
  </body>
</html>

Since the original sb-preview/runtime.js file is a built ES module, this can't be loaded unless you use type="module" or import syntax, but that would result in a request to the file that we can't do. Instead, I wrote a function that compiles the ES module into a browser script using Webpack. That way we can include it in the main bundle. Obviously this removes all the performance benefits of ES modules.

async function createStorybookRuntimeForBrowser(): Promise<boolean> {
  return new Promise((resolve, reject) => {
    webpack(
      {
        entry: path.resolve('node_modules/@storybook/preview/dist/runtime.js'),
        output: {
          filename: 'runtime_browser.js',
          path: path.resolve('storybook-static/sb-preview'),
        },
      },
      (err, stats) => {
        if (err || stats?.hasErrors()) {
          reject();
        }
        resolve(true);
      }
    );
  });
}

You can either run this node function before storybook build as part of your npm script, or you can call it within webpackFinal async handler before returning config. I chose the latter. You can tweak the config further by only running the function and setting the custom template if you are doing a production build of Storybook. That way, your dev version can remain as normal.

This is a complete hack and I hope #472 will remove the need for this nonsense, but I thought I'd share my workaround in case anyone finds it helpful.

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

Successfully merging a pull request may close this issue.

2 participants