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.
Related
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?
What I want to do is add a custom script in package.json file that should run always before start and build scripts.
Things I want to do in my custom script:
Copy the favicon.ico file from /favicons/${process.env.REACT_APP_BRAND}.ico into /public, in order to overwrite the default one
Do a symlink from /src/assets/${process.env.REACT_APP_BRAND} to /src/assets/brand, in order to import images inside code without doing things like dynamic imports (which works but I think it's not their purpose)
I'm a bit lost with the structure of this custom script, and programming languange (its shell, but I'm on MacOS, so, it's better do it in node?)
Thank you.
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.
I am trying to bundle css files with webpack extract-text-webpack-plugin it works great with local files that are int (projects)/src/assets/styles, but I also need bootstrap.css from node_modules and if I try adding it to import b from 'bootstrap/dist/css/bootstrap.css'; the plugin just throws an error that sounds something like this "bootstrap.css Unexpected token (7:5) You may need an appropriate loader to handle this file type." If I add '!style!css!' as described in this question
Webpack Error while including bootstrap 3 it does work, but now it is injected in index.html which may slowdown the overall app. So how do you correctly load the bootstrap style from node_modules? I tried copying it with copy-webpack-plugin, but the copying is performed after the loaders have done their job. so any suggestions?
With a bit more research and debuging the problem was in css loader path, which was pointed to the app source directory, that is why it could not access the node_modules.
I've got a preamble.lessimport file with definitions of standard colors, sizes, mixins etc. that I import in all other .less files. So far, the file was placed in /client and I included it with
#import '/client/preamble.lessimport';
Worked as a charm.
Now, I'm moving all styles to a smart package to make them reusable. How do I include the preamble now?
I've tried putting it as preamble.lessimport in the main package dir and then including with both
#import '/preamble.lessimport';
and
#import 'preamble.lessimport';
Both result in the compile error:
While building package `theme`:
input: Less compiler error: '/preamble.lessimport' wasn't found
Placing the file in a subfolder didn't help. The file is added in package.js and I use less package in both client and server.
How can I properly import that file?
Edit:
I've worked around this issue by importing via relative path:
#import '../../../preamble.lessimport';
However I'm not happy with that solution as the package is on early stage and files inside tends to move a lot. Is there any absolute path I could use?
As of meteor 0.7 you no longer use the .lessimport extension. Your less files should have the .import.less extension.
Take a look at how the bootstrap3-less project imports bootstrap for best use examples.