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

[Bug]: font files are not moved to _assets directory on build #1153

Closed
ties-v opened this issue Dec 19, 2021 · 20 comments · Fixed by #4130
Closed

[Bug]: font files are not moved to _assets directory on build #1153

ties-v opened this issue Dec 19, 2021 · 20 comments · Fixed by #4130
Labels
bug Something isn't working

Comments

@ties-v
Copy link

ties-v commented Dec 19, 2021

What version of Remix are you using?

1.1.1

What version of Node are you using? Minimum supported version is 14.

14.18.1

Steps to Reproduce

Example on stackblitz.com

  1. Run yarn create remix to create a new remix project.
  2. Install a fontsource package in this project, e.g: yarn add @fontsource/aguafina-script
  3. Create the main style sheet: (source)
/* app/styles/main.css */
body { font-family: "Aguafina Script"; }
  1. Add the font style sheet and the main style sheet to root.tsx: (source)
// ...
import fontStyleUrl from "@fontsource/aguafina-script/index.css";
import mainStyleUrl from "~/styles/main.css";

export let links: LinksFunction = () => {
  return [
    { rel: "stylesheet", href: fontStyleUrl },
    { rel: "stylesheet", href: mainStyleUrl }
  ]
}
// ...
  1. Run the development server: yarn dev and visit the page in you browser.

Expected Behavior

Font files (*.woff or *.woff2) from the fontsource package are copied to the _assets folder. Also, the compiled version of the fontsource css points to these font files.

Actual Behavior

Font files are not copied to the _assets folder. Browser receives HTTP 404 when trying to load the font.
image

@ties-v ties-v added the bug Something isn't working label Dec 19, 2021
@ties-v
Copy link
Author

ties-v commented Dec 19, 2021

Related: #185 (comment)

@synaptiko
Copy link

Using the local font from npm is one of the methods described in MUI's docs: https://mui.com/components/typography/#install-with-npm

I would expect this to work out of the box with Remix.

@akbo
Copy link

akbo commented Mar 2, 2022

I found the following workaround on the Remix Discord (credit goes to @kiliman): https://discord.com/channels/770287896669978684/940920958540197889/941007998388690985

For those who don't want to / can't follow the Discord link, add this to your package.json to copy the font files to the bulid folder (change poppins to the name of the font you use):

"build": "remix build && npm run install:fonts",
"postinstall": "remix setup node && npm run install:fonts",
"install:fonts": "rsync -r node_modules/@fontsource/poppins/files/ public/build/_assets/files/"

@melloware
Copy link

melloware commented Jun 27, 2022

If you are using PrimeIcons with PrimeReact then the script is...

Unix:

"build": "remix build && npm run install:fonts",
"postinstall": "remix setup node && npm run install:fonts",
"install:fonts": "rsync -r node_modules/primeicons/fonts/ public/build/_assets/fonts/",

Windows:

npm install copyfiles
"build": "remix build && npm run install:fonts",
"postinstall": "remix setup node && npm run install:fonts",
"install:fonts": "copyfiles -u 3 "./node_modules/primeicons/fonts/*" ./public/build/_assets/fonts/",

@cdev-enter
Copy link

Copying font files manually does not work with the latest version (1.6.4) anymore. Font file references are now cache busted.

Is there a way to disable cache busting for css or make remix copy the font files?

@mcansh
Copy link
Collaborator

mcansh commented Jul 22, 2022

looking into this a bit, looks like esbuild doesn't copy imports/urls from .css files if the loader is set to 'file'

@mcansh
Copy link
Collaborator

mcansh commented Jul 22, 2022

edit: made an example repo - https://github.com/mcansh/playground-1658515042024/tree/main

i did manage to get this working using postcss as a interim step in the build process

// ./postcss.config.js
const path = require("node:path");
const fse = require("fs-extra");

module.exports = {
  plugins: {
    "postcss-import": {},
    "postcss-url": {
      url: (asset) => {
        let { absolutePath } = asset;
        let basename = path.basename(absolutePath);
        let outDir = path.join(
          __dirname,
          "public",
          "build",
          "_assets",
          "fonts"
        );
        let destpath = path.join(outDir, basename);
        if (!fse.pathExistsSync(destpath)) {
          fse.copySync(absolutePath, destpath);
        }
        return "/" + path.join("build", "_assets", "fonts", basename);
      },
    },
  },
};
// ./styles/index.css
@import "@fontsource/aguafina-script/index.css";

using npm-run-all to run both remix and postcss in one tab

"scripts": {
  "dev:css": "postcss ./styles/index.css --output ./app/styles/index.css --watch",
  "dev:remix": "remix dev",
  "dev": "run-p dev:*"
}
// ./app/routes/root.jsx
import fontStyleUrl from './styles/index.css';

@mrmartineau
Copy link

mrmartineau commented Aug 24, 2022

"build": "remix build && npm run install:fonts",
"postinstall": "remix setup node && npm run install:fonts",
"install:fonts": "copyfiles -u 3 "./node_modules/primeicons/fonts/*" ./public/build/_assets/fonts/",

So this method works when running remix build but does not when running remix dev. For some reason when running remix dev there are two build directories generated: one in the public directory and another in the root of the repo (which looks like a duplicate of the directory in the public directory..).

My fix for this was to add a prestart script like so:

"prestart": "npm run install:fonts",
"start": "remix dev"

if you use npm run dev instead, it would look like this:

"predev": "npm run install:fonts",
"dev": "remix dev"

UPDATE:
Also, I used cpy-cli instead of copyfiles so the install:fonts script would look like this for the above scenario:

"install:fonts": "cpy './node_modules/primeicons/fonts/*' public/build/_assets/fonts/"

@dominikj111
Copy link

I think this should be handled by the framework and not by developers using the remix.
I was wondering, so I had a look and the loader for the css is actually a "file" type also mentioned in the #185 (comment).
After change to "css" as esbuild should to cover it I see this in the console.

Remix App Server started at http://localhost:3001 (http://172.20.10.2:3001)
GET / 200 - - 143.124 ms
GET /[object%20Object] 404 - - 9.569 ms

Otherwise I see

...
GET /build/_assets/fonts/primeicons.ttf 404 - - 6.513 ms
GET /build/_assets/fonts/primeicons.woff 404 - - 5.325 ms

I think that esbuild has some problem here or it is used on way which doesn't allow to parse css properly.

@mcansh
Copy link
Collaborator

mcansh commented Aug 30, 2022

I think this should be handled by the framework and not by developers using the remix.

definitely, i took a quick look at this a bit ago - never opened an issue on esbuild yet, but looks like if you use a file loader on a css file it doesn't copy over the url() assets in that file, however if you use a css loader they are copied, but then css file itself is not hashed and the url doesn't get replaced in the build file

https://github.com/mcansh/esbuild-font-files

image

@mcansh
Copy link
Collaborator

mcansh commented Aug 30, 2022

looks like this is what we need to do: evanw/esbuild#1757 (comment) looking into it :)

@KingSora
Copy link
Contributor

KingSora commented Sep 3, 2022

@mcansh I've created a plugin which (hopefully) does the job.. I've tried to touch as less as possible and recycle as many build options as possible #4130

@mcansh
Copy link
Collaborator

mcansh commented Sep 6, 2022

@mcansh I've created a plugin which (hopefully) does the job.. I've tried to touch as less as possible and recycle as many build options as possible #4130

awesome! i'm gonna pull this and check it out ❤️

@ayuhito
Copy link

ayuhito commented Sep 7, 2022

We're actually rebuilding the Fontsource website with Remix so this is huge. Thank you so much for giving up your time for this @mcansh and @KingSora!

@mcansh mcansh linked a pull request Sep 9, 2022 that will close this issue
2 tasks
@github-actions
Copy link
Contributor

🤖 Hello there,

We just published version v0.0.0-nightly-a0823ed-20221015 which involves this issue. If you'd like to take it for a test run please try it out and let us know what you think!

Thanks!

@machour
Copy link
Collaborator

machour commented Oct 20, 2022

Fixed in 1.7.3, thank you @KingSora 🎉

@machour machour closed this as completed Oct 20, 2022
@sergiodevelops
Copy link

copyfiles

Hi Friends !!!
In my case, the development server sources did not load...
I share in this answer my solution (in Remix App FullStack Framework):


// in your root project:

  1. ) add "copyfiles" library in your project:
    yarn add copyfiles
    copyfiles library docs link

// in your package.json file allocated in your root project:
2. ) add "dev:fonts" script in your package.json
For example in my case:

...previus lines
"dev": "run-p dev:*",
"dev:css": "npm run generate:css -- --watch",
"dev:remix": "cross-env NODE_ENV=development binode --require ./mocks -- @remix-run/dev:remix dev",
"dev:fonts": "rsync -r public/fonts/ public/build/_assets/fonts/",
...next lines

// in your css file to load in your route:
3) add your @font-face css rules in your css file loaded from your route:
For example in my case:

@font-face {
    font-family: 'ChekoFontBold';
    src: local('ChekoFont-Bold'),
    url('fonts/Cheko Fonts/Web/ChekoFont/ChekoFont-Bold.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
    url('fonts/Cheko Fonts/Web/ChekoFont/ChekoFont-Bold.woff') format('woff'), /* Modern Browsers */
    url('fonts/Cheko Fonts/Web/ChekoFont/ChekoFont-Bold.ttf') format('truetype'), /* Safari, Android, iOS */
    url('fonts/Cheko Fonts/Web/ChekoFont/ChekoFont-Bold.svg#BloggerSans') format('svg'); /* Legacy iOS */
    font-style: normal;
    font-weight: normal;
    text-rendering: optimizeLegibility;
}

.section-title {
    font-family: "ChekoFontBold" !important;
    text-align: center;
    font-size: 2rem !important;
}

// in your css file to load in your route:
4) add your rule css className in your tsx or jsx file loaded from your route:
For example in my case:

import React from 'react';

export default function About() {
    return (<div className={`section`}>
	<h1 className={`section-title`}>{"Good luck !"}</h1>
</div>);
}

Its worked for me !!
Good luck !

@machour
Copy link
Collaborator

machour commented Oct 30, 2022

@sergioarieljuarez if 1.7.3 didn't work for you here, please open a new issue and provide a public repository reproducing the problem 🙏

@universse
Copy link

universse commented Nov 19, 2022

hi, any tip on how to get the url for the hashed font file referenced in the css file? I'm trying to preload the font via route module's links function, but esbuild throws an error when importing the font file from node_modules.
image

@machour
Copy link
Collaborator

machour commented Nov 19, 2022

@universse please ask support questions in the Discussions tab.

@remix-run remix-run locked as resolved and limited conversation to collaborators Nov 19, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.