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.
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?
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.
I'm using Webpack with Storybook and need to include a JavaScript library file in an HTML file via a script tag. Unfortunately, I get a 404 error indicating that the file was not found (the file's path is based on my local filesystem and is correct). How do I inform Webpack regarding where to look for my library or "static" files?
Add files in entry object in webpack.config.js
entryPoint = {
app: ['path/to/script', 'path/to/script2','./index.js'],
};
This will make sure that you have the library loaded when you have run index.js (entry point of project).
More on Webpack entry points.
Am I correct in understanding that Webpack transforms everything you have into JS code only? So that even if you have CSS, it will be turn into JS (in a bundle) as long as you have the correct loader?
Loaders can transform files from a different language like
CoffeeScript to JavaScript, or inline images as data URLs. Loaders
even allow you to do things like require() css files right in your
JavaScript!”
Loaders won't convert CSS into JavaScript but it will allow you to import CSS files right from your JavaScript file. For e.g. you have components based application architecture and each component has it's own CSS, you can load css right from component's JS file.
Like this (in your app.js)
import styles from './app.css';
OR more generic
import './app.css';
From Official site
Loaders can transform files from a different language (like
TypeScript) to JavaScript, or inline images as data URLs. Loaders even
allow you to do things like import CSS files directly from your
JavaScript modules!
Example
For example, you can use loaders to tell webpack to load a CSS file or
to convert TypeScript to JavaScript. To do this, you would start by
installing the loaders you need:
npm install --save-dev css-loader
npm install --save-dev ts-loader
And then instruct webpack to use the css-loader for every .css file and the ts-loader for all .ts files:
I'm looking for a solution to a pretty common webpack annoyance: within every folder in our app we need an index.js file that requires every other .js file within that folder and then exports them all so that webpack understands how we'd like to import them.
Is there any way to automate this via a custom Resolver / Loader?
Thanks in advance!