How to use spriting with Webpack and Sass? - javascript

I am moving my build system from Grunt with custom tasks to Webpack. As for JavaScript modules it works great, but I'm not so sure what to do with my Sass stylesheets.
I have dependencies on Sass files in my AMD modules, which Webpack can read and generate bundle.css from. But I would ideally like to have my build pipeline generate sprites using spritesmith, then copy the images to the build dir and use the Sass mixins to generate correct CSS rules.
I have researched this a lot both on SO and Google, but haven't found anyone doing similar scenario. Should I use solely webpack? Or should I maybe have separate Grunt task watching the images, generating sprites and then run Webpack over that?

I have a similar problem, I have a directory full of png files that I need to convert to CSS so that a div with the correct class name will load the image. I would like to use url-loader so that small files are inlined.
The problem is of course that you can't specify a directory as something a loader should load, only existing files.
My solution is to create a custom loader in the png dir and give it itself as input, so it can glob the files in its own dir and export the CSS with all the require statements for the png files.
This is the webpack entry for it:
'!!style!css!./resources/images/images-as-css-loader.coffee!./resources/images/images-as-css-loader'
The loader code (coffeescript but you get the idea):
glob = require 'glob'
path = require 'path'
sizeOf = require 'image-size'
module.exports = (dummy) ->
this.cacheable true
dir = path.dirname this.resourcePath
entries = for file in glob.sync "#{dir}/*.png"
#addDependency file
className = (path.basename file, '.png')
imgDim = sizeOf file
"""
.#{className} {
width: #{imgDim.width}px;
height: #{imgDim.height}px;
background-repeat: no-repeat;
background-image: url('~!!url?limit=1024!#{file}');
}
"""
# Return CSS text
return entries.join ''
You can then use the webpack text extract plugin to move the CSS to a file, which I do for the production build. For dev I just let the style loader inject it.

I had similar problem, the only solution I've been able to come up with was to write my own plugin.

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?

VueJS: Trying to compile two CSS files in /dist

I just began using Vue and I'm hitting a wall while trying to compile SCSS into separate files. I understand that any SCSS that I'm writing within components will be compiled into a single file (/dist/css/app[hash].css), but I would like separate files which aren't imported into any component for external use.
I have several SCSS files (frames.scss, lists.scss, and tables.scss ) that I would like to be compiled, minified, and prefixed into their own CSS files alongside the aforementioned CSS file.
I would like the build structure to look something like this (with the external CSS file existing alongside the app CSS file):
dist/
css/
app[hash].css
frames.css
lists.css
tables.css
I have very little experience with Webpack, so my vue.config.js file is currently empty and my postcss.config.js file is below:
module.exports = {
plugins: {
autoprefixer: {}
}
}
I've searched all over StackOverflow for a solution to no avail, so any help would be greatly appreciated!
For webpack 4, I think you want to look at mini-css-extract-plugin.
its a webpack plugin that, by, default, creates different files per input. You can use this with scss as you would expect. https://stackoverflow.com/a/53180597/6646536 might be a good example.
There is a similar tool i've used for webpack 3 here:
https://github.com/webpack-contrib/extract-text-webpack-plugin

Extracting a javascript file from webpack build

I am using webpack for a project where I need to have a javascript config file as part of the built files, but I cannot figure out how to do that.
So I need to have these files in the output:
index.html
app.js
config.js
I figure I need to either:
1) Copy the config.js file from the source folder to the build folder with CopyWebpackPlugin, or
2) Include the file in the compiled bundle and then extract it with ExtractTextWebpackPlugin.
I have tried dozens of different ways of configuring this, but when trying with the copy method, I get the file both inside the app.js bundle AND as a separate file. When I try with the extract method, I cannot seem to figure out how to extract javascript from the main bundle. The docs all seem to explain how to extract css.
How would I go about something like this?
You should be able to accomplish this by using multiple entry points.
https://webpack.js.org/concepts/entry-points/
entry: {
main: './path/to/file/app.js',
config: './path/to/file/config.js'
}
output: {
filename: 'output/path/[name].js'
}
A more complex option, which is typically used for vendor files, would be to use code-splitting.
https://webpack.js.org/guides/code-splitting/

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.

using requirejs optimizer to minify to a single javascript and single css

I am writing jQuery plugin and using requirejs in order to make my plugin modular and easier to code.
The plugin has also its own css files. Now, I want to combine and minify all the js files and css files. I am using r.js to so it. Here is the build.js configuration file that knows how to concatenate and minify js files into one file:
({
baseUrl: 'js/plugin',
optimize: 'none', // none, uglify or uglify2
wrap: true,
name: '../vendor/almond',
include: 'main',
out: '../dist/jquery.my-plugin.min.js'
})
How can I add an option to minify also css file? I saw the cssIn option, but where do I tells r.js wha is the output name? Do I need to use modules? If so, how?
r.js automatically inlines contents of #import url(...) links in all .css files found in the project directory (thus concatenating multiple files into one master stylesheet).
In your current build configuration, however, with only baseUrl specified, r.js doesn't even know about the CSS folder (which is, presumably, somewhere in ../../style/ relative to js/plugin/).
You'd have to add the appDir and dir properties to your buildconfig file (both explained in detail in the example config file) and set project root (ie. appDir) to directory that contains both JS and CSS folders.
Please note that, as mentioned in the documentation, adding appDir will require changing value of baseUrl to be relative to appDir.

Categories

Resources