webpack-encore icon indicating copy to clipboard operation
webpack-encore copied to clipboard

Wrong path fonts

Open dayze opened this issue 8 years ago • 43 comments

When I include semantic or bootstrap in my main.js I end up with a 404 not found error for the fonts

Apparently, the output path of fonts go to the root of my web server like this

http://localhost/build/fonts/icons.woff2

dayze avatar Jun 16 '17 09:06 dayze

Hey @dayze!

Can you post your webpack.config.js file and also the code for any relevant other files (like main.js)?

weaverryan avatar Jun 16 '17 22:06 weaverryan

Hi,

webpack.config.js

var Encore = require('@symfony/webpack-encore');

Encore
// directory where should all compiled assets will be stored
    .setOutputPath('web/build/')

    // what's the public path to this directory (relative to your project's document root dir)
    .setPublicPath('/build')

    // empty the outputPath dir before each build
    .cleanupOutputBeforeBuild()

    // will output as web/build/app.js
    .addEntry('app', './assets/js/main.js')


    // will output as web/build/global.css
    .addStyleEntry('global', './assets/css/global.scss')


    // allow sass/scss files to be processed
    .enableSassLoader()

    // allows legacy applications to use $/jQuery as a global variable
    .autoProvidejQuery()


    .enableSourceMaps(!Encore.isProduction())



// create hashed filenames (e.g. app.abc123.css)
// .enableVersioning()
;

var webpackConfig = Encore.getWebpackConfig();
webpackConfig.module.rules.push({
    test: /\.vue$/,
    loader: 'vue-loader'
});
webpackConfig.module.rules.push({
    test: /\.js$/,
    loader: 'babel-loader',
    exclude: /node_modules/
});

// export the final configuration
module.exports = webpackConfig;

main.js

import Vue from 'vue/dist/vue'
import App from './app.vue'

require('semantic-ui/dist/semantic.min.css')

Errors

GET http://localhost/build/fonts/icons.woff2 
GET http://localhost/build/fonts/icons.woff 
GET http://localhost/build/fonts/icons.ttf 

dayze avatar Jun 19 '17 07:06 dayze

Same issue here, with similar configuration. The situation seems to be that my app doesn't run on a ground-level domain, but on a alias on apache:

Alias /mySymfonyApp /var/www/html/mySymfonyApp/web

So webpack is trying to create the src: url() paths with /build/fonts/myFont.eot, when it should be /mySymfonyApp/build/fonts/myFont.eot.

webpack.config.js:

var Encore = require('@symfony/webpack-encore');

Encore
    .setOutputPath('web/build/')

    .setPublicPath('/build')

    .cleanupOutputBeforeBuild()

    .addEntry('app', './app/Resources/js/app.js')

    .addStyleEntry('global', './app/Resources/scss/global.scss')

    .enableSassLoader({
        resolve_url_loader: false
    })

    .autoProvidejQuery()

    .enableSourceMaps(!Encore.isProduction())
    
    // create hashed filenames (e.g. app.abc123.css)
    // .enableVersioning()
;

// export the final configuration
module.exports = Encore.getWebpackConfig(); 

global.scss:

@charset 'utf-8';

$fi-path: "~foundation-icon-fonts/";

@import '~foundation-sites/assets/foundation';
@import '~foundation-icon-fonts/foundation-icons';

Resulting global.css:

// [...]

@font-face {
  font-family: "foundation-icons";
  src: url(/build/fonts/foundation-icons.eot);
  src: url(/build/fonts/foundation-icons.eot?#iefix) format("embedded-opentype"), url(/build/fonts/foundation-icons.woff) format("woff"), url(/build/fonts/foundation-icons.ttf) format("truetype"), url(/build/images/foundation-icons.svg#fontcustom) format("svg");
  font-weight: normal;
  font-style: normal; }

// [...]

localhost/build/fonts/foundation-icons.ttf obviously 404s, the correct path would be localhost/mySymfonyApp/build/fonts/foundation-icons.ttf

heitorvrb avatar Jun 19 '17 18:06 heitorvrb

@heitorvrb Ah, thanks for the extra info! If you're deployed under a subdirectory, that should be reflected in your setPublicPath:

// this is your *true* public path
.setPublicPath('/mySymfonyApp/build')
// this is now needed so that your manifest.json keys are still `build/foo.js`
// i.e. you won't need to change anything in your Symfony app
config.setManifestKeyPrefix('build')

You can see an example of this in the tests as well: https://github.com/symfony/webpack-encore/blob/db980b4018104b8f16a9f83111078ce86e7b76ad/test/functional.js#L180

Webpack must be aware of the true public path, because if you use "code splitting", then webpack itself will make AJAX requests for assets (so it needs to know the real path). That's why the config lives in webpack.config.js, instead of allowing your app (i.e. Symfony) to "fix" the subdirectory.

Let me know if that helps! I'll open an issue on the docs about this.

weaverryan avatar Jun 20 '17 15:06 weaverryan

It worked. Thanks for the help.

heitorvrb avatar Jun 20 '17 20:06 heitorvrb

It worked too, thanks !

dayze avatar Jun 21 '17 06:06 dayze

What if my web root changes depending to the environment I'm deploying to? On my local development environment, the web root will be /my-nth-app/web/build whereas on the production server, it will just be /build. What would be the recommended way to make this dynamic, or at least, configurable?

vctls avatar Oct 09 '17 11:10 vctls

@vctls Maybe you could use Encore.isProduction() to set the web root dynamically?

Encore.setPublicPath(Encore.isProduction() ? '/build' : '/my-nth-app/web/build');

Lyrkan avatar Oct 09 '17 12:10 Lyrkan

@Lyrkan I will do that, thank you :) It feels a little hacky, though. I wonder if there's any way of detecting the web root.

vctls avatar Oct 09 '17 12:10 vctls

@Lyrkan what if I use artifact-based deploying and the builder do not really know where the artifact would be deployed to?

Is it possible just make path relative to manifest?

scaytrase avatar Nov 05 '17 12:11 scaytrase

Hi @scaytrase,

I guess you would need to call setPublicPath with a relative path... which isn't allowed right now:

https://github.com/symfony/webpack-encore/blob/799720602aab2069f827704e4a6d672d03d38d76/lib/WebpackConfig.js#L122-L127

@andyexeter had a similar issue here: https://github.com/symfony/webpack-encore/issues/88#issuecomment-340537827

We could probably add an allowRelativePath parameter to that method in order to disable that check... what do you think @weaverryan?

Lyrkan avatar Nov 05 '17 13:11 Lyrkan

@Lyrkan commenting this error and passing relative path makes internal CSS files to import like

basedir/build/build/fonts/fontawesome.ttf

The build doubles since CSS file is placed inside the build and it calls relative build/fonts/.../

So we really need the possibility to rewrite the paths

scaytrase avatar Nov 05 '17 14:11 scaytrase

@weaverryan thanks for the release 0.17.2. I tested it and it kind of works. But as you already expected, its not a solution that solves all problems. By setting .setPublicPath('./') to a relative value and .setManifestKeyPrefix('build/') the linked resources in generated files (like url to fonts in css files) are relative, so first goal achieved.

But the next problem is that these relative paths become also part of the manifest.json:

  "build/app.css": "./app.css",
  "build/app.js": "./app.js",
  "build/fonts/fontawesome-webfont.eot": "./fonts/fontawesome-webfont.674f50d2.eot",

That now collides when using the JsonManifestVersionStrategy as the path to my assets are wrong:

    assets:
        json_manifest_path: '%kernel.project_dir%/public/build/manifest.json'

and

<script src="{{ asset('build/app.js') }}"></script>

results in

<link rel="stylesheet" href="/./app.css">

We could now disable the JsonManifestVersionStrategy, even though we would loose the option for .enableVersioning(Encore.isProduction()). But even with deactivated versioning, my required assets like images will still have a hashed filename, e.g.require('../images/default_avatar.png'); will result in a file called public/build/images/default_avatar.fc197350.png and therefor I can't use {{ asset('build/images/default_avatar.png') }} for it.

All in all your fix might solve some problems, but I guess it doesn't help with the usecase of generating assets in a way that they work both on root level and in a subdirectory in combination with SF4 and Twig. But I am new to encore and webpack, so I might miss something, any help would be great.

kevinpapst avatar Jan 30 '18 21:01 kevinpapst

I’m going to re-open so we can process the new info

weaverryan avatar Jan 30 '18 23:01 weaverryan

@kevinpapst couldn't you do simply

.setPublicPath('build')

or am I missing something?

stoccc avatar Feb 01 '18 15:02 stoccc

@stoccc before the patch it was required that public path starts with /

scaytrase avatar Feb 01 '18 16:02 scaytrase

@stoccc No, the public path is not only used for building the manifest.json, it is used to reference assets like font urls within scss files. So a generated css file, lets say build/app.css, would reference a font with url(build/fonts/myfont) and that would result in a 404. Its relative location to the css file is fonts/myfont as @scaytrase wrote above. My usecase could be solved, if we would be able to set the publicPath for compile time independent from the publicPath prefix used in the manifest.json. But I couldn't find a setting in webpack config for that.

kevinpapst avatar Feb 01 '18 16:02 kevinpapst

I had same problem. and I solve like this

I have public/build folder. This folder for JS/CSS. I just add this line from

.setPublicPath('/build/')

to

.setPublicPath('/public/build/')

Actually, I'm not sure. Is it secure way to use?

BerkhanBerkdemir avatar Feb 02 '18 01:02 BerkhanBerkdemir

@weaverryan it seems that 0.17.2 has not yet been published to npmjs https://www.npmjs.com/package/@symfony/webpack-encore

stoccc avatar Feb 02 '18 09:02 stoccc

@stoccc and everyone who wants to test. you can change your package.json to

"@symfony/webpack-encore": "git://github.com/symfony/webpack-encore.git#0.17.2",

kevinpapst avatar Feb 02 '18 10:02 kevinpapst

@kevinpapst @weaverryan

I am in this scenario:

  • my symfony app is deployed in production under a subdirectory, e.g. www.myhost.com/apps/mySymfonyApp
  • the same app is under www.myhost.com/some/development/path/mySymfonyApp for development purposes and under www.myhost.com/some/demo/path/mySymfonyApp for demo purposes
  • if possibile, I don't want to care in my config what is the path where the app is deployed

I have deleted these two lines of code in version 0.17.2 (they add a traling slash if it is not present), so that I can have a public path defined as '' (otherwise it is transformed to '/').

With this configuration in webpack.config.js

.setOutputPath('public/build/')
.setPublicPath('')
.setManifestKeyPrefix('build/')

all works correctly:

  • I can access assets from twig with

     {{ asset('build/app.js') }}
    
  • And if some scss file (like in Bootstrap) uses some other file (like glyphicons fonts) they are referenced properly. For example glyphicons-halflings-regular.eot is referenced as url(fonts/glyphicons-halflings-regular.f4769f9b.eot) in compiled css.

I am wondering: is this solution acceptable or are there some other consequences/scenarios which I can't figure out (I'm new to encore/webpack and nodejs..)?

If it is acceptable, we could test if publicPath is not empty before adding the trailing slash.

stoccc avatar Feb 02 '18 11:02 stoccc

I tried many combinations, but missed that the slash is automatically added on an empty string. I can confirm that your solution works @stoccc. Thanks, good spotting! The manifest.json is generated correctly and the assets have a proper relative URL. Versioning works and I can use the JsonManifestVersionStrategy. @weaverryan any thoughts on an empty publicPath?

kevinpapst avatar Feb 02 '18 12:02 kevinpapst

@weaverryan I can confirm that @stoccc way worked to mee to with latest version installed from github (like @kevinpapst referenced). Commenting out these two lines makes base directory changing work without touching any code or configs

scaytrase avatar Feb 02 '18 20:02 scaytrase

Awesome! Then we should create a PR! I need to do some git blame to make sure I remember why that trailing slash is so important usually. However, based on why I’ve heard, we may be able to skip that trailing slash of the publicPath argument does not have the starting slash. Basically, you’d opt in to absolute paths or relative.

So yea - can someone create a PR? We have a great test suite in functional.js - it would be pretty easy to setup a seriously solid test to make sure the edge cases all work.

weaverryan avatar Feb 11 '18 14:02 weaverryan

yes I vote for @stoccc +1

MasterB avatar Feb 12 '18 13:02 MasterB

Any news on this issue?

eberhapa avatar Mar 08 '18 09:03 eberhapa

I'm sorry but in these weeks I can't work on it.

2018-03-08 10:20 GMT+01:00 Patrick [email protected]:

Any news on this issue?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/symfony/webpack-encore/issues/26#issuecomment-371428864, or mute the thread https://github.com/notifications/unsubscribe-auth/AXqHI2Azkt686RK2wO0EgJGklO7e67cUks5tcPfvgaJpZM4N8PKQ .

stoccc avatar Mar 08 '18 23:03 stoccc

@stoccc solution does not seem to work when using dynamic import (promise).

idybil avatar May 25 '18 12:05 idybil

there are multiple cases not working:

  • dynamic JS imports
  • images required from JS to get their path to insert in the DOM

In both cases, webpack needs to know the path to put them in the DOM, and a relative path here would be relative to the document (so being on / or on /blog/2018/hello.html requires a different relative path).

stof avatar May 25 '18 15:05 stof

Two cents: I've been battling this for days now. IMHO Community Focus for Symfony and other packages always seem to be on a single app running on a single web server under the root folder. In reality we run many separate apps on a single web server with each app running under different sub folder path. Don't get me started about issues trying to run behind a corporate firewall.

i.e. http://example.com/app1 -> /apps/app1/public http://example.com/app2 -> /apps/app2/public

My Current Issue: My main issue was the addition of double build "/build/build/" for font-awesome woff2 and woff url links inside my layout.css file.This occurred when using public path set to "build/" and no prefix. Just FYI, the warning by setPublicPath about not starting with '/' is very annoying. My app won't even work if it starts with '/', except for server:run, but I'm not using that in production.

Currently using Symfony 4.1 with

        "@symfony/webpack-encore": "^0.19.0",
        "bootstrap": "^4.1.1",
        "font-awesome": "^4.7.0",

My Solution I seem to have found partial solution that works as long as I don't use enableVersioning. Here are relevant Encore settings that work for both http://localhost:8000 and http://example.com/app1/ URL's.

    .setOutputPath('public/build/')
    .setPublicPath('../build')
    .setManifestKeyPrefix('../build')
    //.enableVersioning(Encore.isProduction()) 

Symfony Framework issue: Did not add framework.assets.json_manifest_path but I am using framework.assets.version to set unique version number to asset. For some reason Symfony Framework ignores the manifest.json and marks asset using unversioned name. I was able to use Symfony versioning for now.

Using PublicPath = '../build' and json_manifest_path, this is sample of what occurred imanifest.json =

  "../build/layout.css": "../build/layout.a0beb1a4.css",
  "../build/layout.js": "../build/layout.3bc13eb7.js",

Web page =

    <link rel="stylesheet" href="/app1/build/layout.css">
    <script src="/app1/build/layout.js"></script>

Settings: framework. assets.json_manifest_path: '%kernel.project_dir%/public/build/manifest.json'

Not sure if I should create issue in Framework for this until Encore issues are resoled (if possible).

Thanks, Dave

dspiegel avatar Jun 11 '18 01:06 dspiegel