webpack resolve error with packaged css file referencing an image - javascript

I'm working on a Vue component library built via VueCLI (and using Storybook Js, Bulma, and Buefy) and I am having issues consuming the CSS downstream. Specifically when I import the CSS file from my package, I am getting Webpack errors with referenced images.
For example, in my upstream src scss files I have a file called "notice-badge.scss" and am referencing background images like so:
.notice-badge img {
background-image: url('#/assets/img/warning-dark.svg');
}
and my src directory structure looks like:
my-app/
|--src/
|--assets/
|--scss/
|-- notice-badge.scss
|--img/
|--warning-dark.svg
|--fonts/
|--vue-components/
and I build the packages with this command which produces no errors.
vue-cli-service build --target lib --name my-ui-components ./src/index.ts
This outputs my JS, a CSS file, and 2 directories (img and fonts) into my "dist" directory. The images listed in my errors are infact inthere.
So over in another Vue cli app (and later Nuxt) I will be importing the CSS file and Vue components but I am getting a "can't resolve" error on that warning-dark.svg file:
Can't resolve /img/warning-dark.a45b259b.svg in /Users/myname/sites/my-app/ui-components/dist. My package also contains font awesome font files too (a business decision to include this all up stream)
So how can I get my downstream Vue CLI app to resolve the images and fonts referenced inside my node_modules dir?

You have (at least) 3 options:
Inline the images/fonts as data URLs.
Use a relative path in the output and require apps that install your package to move the image directory to the same path as the built CSS file.
Don't ship built CSS, but instead source SCSS files. That way file loading/moving can be handled with WebPack configuration in the app that uses it (using file_loader. You can include example configuration in your package to make this easier.
If you're writing a Vue component library, it probably makes most sense to use method 3. However from your description it seems like this may not be an option (the business decision you mention). Method 2 might be viable but I didn't try it nor seen someone else suggest it.
Inline
This method probably is easiest and has best performance. If your other SVGs are similar to the examples, it seems like they should all be relatively small files. There's few reasons for a component library to ship big images, so this might be sufficient for your use case.
If you're using WebPack 5, you can inline assets using "Asset Modules".
module: {
rules: [
{
test: /\.svg/,
type: 'asset/inline'
}
]
}
If you tried this, you may have run into the following problem.
Since Sass implementations don't provide url rewriting, all linked
assets must be relative to the output.
If you pass the generated CSS on to the css-loader, all urls must be
relative to the entry-file (e.g. main.scss).
If you're just generating CSS without passing it to the css-loader, it must be relative to your web root.
You can try replacing url('#/assets/img/warning-dark.svg') with url('../img/warning-dark.svg') (or whatever the path relative to the entrypoint is). Does it now properly inline them?

Related

Vue 2 with Vue CLI - How to make src/static static so I can use images that are in there?

I'm trying to package my Vue CLI app to package src/static/xyz.png such that I can reference it as /static/xyz.png.
The Vue docs don't really show how to do this. I need a vue.config.js but between here:
https://cli.vuejs.org/guide/webpack.html
and here:
https://cli.vuejs.org/guide/html-and-static-assets.html#html
I can't figure out what I need to do. Any ideas? I've tried lots of webpack stuff but don't know webpack well enough, evidently...
In Vue CLI projects, files under public/ are automatically bundled as static assets, so you don't need a custom config for this. Your image should be stored in:
<projectRoot>/public/static/xyz.png
Then you'd reference them in your markup like this:
<img src="/static/xyz.png">
Note that these static assets are not run through Webpack, so they won't be optimized (i.e., the image file size might be unnecessarily large).

Using webpack and publicPath for static resources

The following question was rewritten, because I have now a working solution, but no answer to the question above.
The repository that shows different scenarios how to use resources packed with webpack is named example-webpack-dynamic-resources. It contains 3 modules:
inline: a solution, but not useful in my context (many resource files)
file: a solution by using the plugin webpack-require-from
public-path: no solution yet, shows how I would like to use __webpack?public_path__.
I think I have read any resource about webpack and publicPath and __webpack_public_path__, but I don't get it to work. I try to dynamically change the path to static resources, but it fails.
Here is my context:
I build a Javascript library that will be used on web pages (HTML, CSS, Javascript).
It provides a lot (>100) static resources to small image files, combined > 500 KB. Only a fraction of it will be used by the user looking at the web site.
Therefore I would like to pack the CSS into the bundle, but keep the image resources in a directory located on the server somewhere. The default path to it will be /img.
As long as I use the same structure (which means, images only under ROOT/img/**, everything is ok.
But the users of the library should be able to configure the path to the image resources on their will.
You will find all relevant files in my example repository example-webpack-dynamic-resources in the module public-path-resources.
webpack.js: Use file-loader for images, which are referenced in CSS files. CSS will be inlined by style-loader and css-loader.
src/public-path.js: Define the global variable with a default (no environment variable).
src/index.js: require first public-path, then the logic.
examples/exam1-root/index.html: Tries to use the assets in the sub directory lib, sets the value therefore to __webpack_public_path__ = '/lib/. Not working.
examples/exam2-different-dirs/index.html: Moves the library to a different dir (not relevant), but uses the originally defined directory pgnv-assets for the assets. Working.
examples/exam3-non-standard-dirs/index.html: Try to use instead my-assets as directory for the assets. Not working.
How could the __webpack_public_path__ defined at runtime in the index.html file?

CSS not added to /dist folder using Webpack 4 and MiniCssExtractPlugin

Issue
Would any Webpack config experts out there be able to tell me why I can't extract my css into the dist folder when running npm run build?
Repo is here: https://github.com/damodog/webpack4-boilerplate
Further info
To summarise, I've been working through the Webpack Guide docs and everything was going well. js and css was getting injected into my index.html file via <link> and <script> tags respectively. I've installed various loaders, plugins etc and split my configs out into common (shared), dev and prod files (as per the docs) and life was good.
I happened to make some tweaks which included looking at code splitting dynamic imports, adding aliases for paths, moving js into js folder etc and noticed when I ran a build npm run build all of a sudden my css wasn't getting added to the dist folder. I reverted my trial changes for the dynamic import stuff and tried reverting the other changes but am still getting the same issue. Annoyingly I hadn't added git at this point so didn't have a clear picture of the 'tweaks' I'd made to locate what I'd changed.
What happens
When I run my watch task npm start the styles.scss file (imported into the main index.js file) get's compiled into css and the resulting app.css file gets injected into the index.html page when viewed in my local host. All gravy.
<link href="css/app.css" rel="stylesheet">
When I run npm run build the css file should get copied over dist folder, a hash id should get added and the css should be minified. This was working (like I said above) and I could see the css file in the build steps (see first Asset below. Btw disregard the difference in js bundled files here compared to the next screenshot. This was when I was playing with code splitting).
Now when I run this the css isn't bundled up (see below).
I think it could be something to do with mini-css-extract-plugin but I've configured this as per the docs using the advanced configuration example (I've split their example out which is in one config file as I have separate config files for dev and prod).
I literally cannot see why this is happening.
Help me SO readers. You're my only help...
I cloned your repo and experimented with it. In your package.json, you've set: sideEffects: false. This causes the imported stylesheets to be lost in the process of tree shaking. This is described in the docs:
A "side effect" is defined as code that performs a special behavior
when imported, other than exposing one or more exports. An example of
this are polyfills, which affect the global scope and usually do not
provide an export.
and
Note that any imported file is subject to tree shaking. This means if
you use something like css-loader in your project and import a CSS
file, it needs to be added to the side effect list so it will not be
unintentionally dropped in production mode
So change your side effects in package.json to "sideEffects: ["./src/scss/styles.scss"] and it will be output to the destination folder when in production mode.

Criticalcss on initial build with webpack fails

So I'm using Webpack to bundle up my js and css.
I've added the Webpack-plugin-critical to output an external css file featuring critical styles. This file gets added to my (twig) template.
It works fine if I run Webpack a second time, though the initial build fails and I get an error saying it can't find the primary generated css file. How do I expose the primary css file output from ExtractTextPlugin to Webpack-plugin-critical allowing it to consume the file and produce a critical css file on initial build?
I think it is impossible.
https://github.com/nrwl/webpack-plugin-critical/blob/master/src/critical.ts#L129
You can see that webpack-plugin-critical use the event hook "emit" which assets files are not generated by webpack compiler yet.
In the other hand, I recommend that you could use an other independent webpack config for generate critical css specifically.
For any one stuck on this. Use this plugin; https://www.npmjs.com/package/html-critical-webpack-plugin
It builds the critical styles AFTER the sass has been compiled.

Angular 2 avoid compiling images defined in CSS

I have a styles.css in my Angular 2 application.
It's referred to in app.styles object in .angular-cli.json.
Inside that css I have urls to background images, e.g:
.bg-game {
background-image: url("assets/app/game_bg_768.jpg");
}
When compiling the app, it seems Angular 2 copies the files from their location into the root folder of the compiled app and adds to its name a random hash.
For instance assets/app/game_bg_768.jpg will be copied to dist/ (compiled app folder) as game_bg_768.023f195663c85e8f0322.jpg.
Then in the styles css compiled by Angular 2, the reference will be changed accordingly:
.bg-game {
background-image: url("game_bg_768.023f195663c85e8f0322.jpg");
}
I'd like to disable that whole process, only for images that are linked to in CSS, I don't want to disable random hashes generation for the whole app.
The reason behind this - I'm preloading assets/app/game_bg_768.jpg before the game starts, but since a different url is specified in the compiled css, during the game another request is made to load game_bg_768.023f195663c85e8f0322.jpg.
Another reason is, I'd like my images to remain in my assets folder, I don't want them to be duplicated into the root folder of the compiled app.
You can use absolute URLs to avoid it.
.bg-game {
background-image: url("/assets/app/game_bg_768.jpg");
}
However, after you do that, the compiler won't check if the images exist in assets directory anymore.
Also, if you are deploying your app to a subdirectory of the domain, the browser will look for the asset on /assets instead of /subdirectory/assets. Using base-href or deploy-url won't help.
As an idea, you need to reconfigure webpack settings and set corresponding loader settings.
BUT, AFAIK by default AngularCLI doesn't provide a visible config file for webpack, so, you need to make some tricks for that and keep in mind aftermath or you can try to play with assets configuration in .angular-cli.json

Categories

Resources