Bundling separate CSS with Webpack - javascript

I've got Webpack working with style-loader and sass-loader, but can't figure one thing out:
I have two separate "stylesheet" bundles (our normal app, and a custom-skin version for a client). If I require them in separately, it'll still get output as 1 file (bundle.css). I also tried setting the sass source files as entry points, but that gave me this error:
ERROR in Entry module not found: Error: Cannot resolve 'file' or 'directory' /Users/slangbroek/Projects/app-name/app/src/styles/mobile/mobile in /Users/slangbroek/Projects/app-name/app/src
for both stylesheet-entrypoints. Does anybody have any idea how to accomplish this with Webpack?

You could use two .js entrypoints, one for the normal app and one for the custom-skinned version. If the only difference in these were the stylesheets, you may want to have 3 entrypoints, one for the app .js that both projects consume, and an entrypoint for each .scss file. All those entrypoint files would do is require the stylesheets.
Its pretty bizarre, but I believe that'd be the only pure webpack solution. Of course, you could consider using webpack in conjunction with gulp/grunt/etc, and use the task runner to bundle with webpack and compile your scss files as well.

Related

webpack resolve error with packaged css file referencing an image

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?

Webpack watch file changes and trigger loader for other files

I'm looking for a way to watch changes on files (sass files precisely) and execute a loader on other files (js files) with webpack.
The goal is to detect sass changes and recompiling all the javascript files with the babel-loader, because they might import it through the styled-jsx plugin.
I'm stuck in the "loader" concept and can't figure out how to get other files when testing for /.scss$/
You don't need to do anything by yourself if you using scss modules with webpack (more about module concept in the webpack docs.
What webpack does - it starts at entry point (you can specify one or multiple entrypoints, if you don't, default src/index.js would be used). And then builds dependency trees between modules (which can have any file extension as long as there's a specific loader that can turn file into module). Webpack then watches all files and rebuild all modules that have a dependency on changed file. So, if you import the .scss file in, let's say, your entrypoint
import './styles.scss';
// ...
It would rebuild automatically when styles.scss changes
You need to import your .scss file(s) under one of your .js files so that webpack actually picks up the changes.
Then, all loaders you have configured will be applied automatically based on which file type they should target.

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.

Webpack proper bootstrap loading with extract-text-webpack-plugin

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.

Javascript project structure for dev and production using npm and grunt

I am trying to structure javascript files in a project. I have used NPM to manage the modules and planning to use Grunt to concatenate and compress the js and css files for deployment.
I am currently using the following structure
-[project root]
-- [node modules] :packages such as requirejs, jquery, semantic-ui etc using npm
--[war]
---[Dev]
----[css] multiple css files from modules (Question 2:?)
----[js] multiple js files from modeuls (Question 2:?)
- Gruntfile.js :for concatenate and compress
---[Production] -
----[css]:This is where the compressed and concatenated css files are kept
----[js] :This is where the compressed and concatenated js files are kept
Question 1: Is the above approach to structure the project correct ? Any other recommendations which allows to manage the packages, dev and production files.
Question 2: Can NPM or another tool allows me to pick up the js and css files from the [node modules] folder and place them to (dev>>css or dev>>js) folder ? If am doing this manually how do I track the versions ? Seems like I am missing something here, there must be a better solution.
Suggestions/recommendations/comments are much appreciated.
Thanks
The question is a bit too wide for SO format, but in general your structure is good. Instead of copying files from node_modules, you have your own JavaScript files under js and you import/require them to your own files.
//foo.js
//ES6 style imports
import {Foo as Bar} from "biz";
//Common JS style requires
var Bar = require("biz");
//AMD style requires
require(["biz"], function (Bar) {
If you want to use your node_modules in a browser, you'll want to bundle them using Browserify, Webpack, Rollup or similar. To automate this, you can easily use Grunt tasks such as grunt-browserify together with grunt-watch.
Same applies for your CSS files: You store your own files under css and if you need CSS files from node_modules you can import them to your own files: if you are using some preprocessor (such as SASS or LESS), the preprocessors usually inline your imports when building the .css-file. If you are just using plain .css files, see grunt-css-import for example.

Categories

Resources