vitePreprocess in SvelteKit triggers Preprocessor dependency "sass" not found when using scss - sass

I have a brand new project using SvelteKit. By default, vitePreprocess is used to handle scss and other files, as described in the docs:
vite-plugin-svelte offers a vitePreprocess feature which utilizes Vite
for preprocessing. It is capable of handling the language flavors Vite
handles: TypeScript, PostCSS, SCSS, Less, Stylus, and SugarSS. For
convenience, it is re-exported from the #sveltejs/kit/vite package. If
you set your project up with TypeScript it will be included by
default:
// svelte.config.js
import { vitePreprocess } from '#sveltejs/kit/vite';
export default {
preprocess: [vitePreprocess()]
};
However, if I use lang="scss" in my files:
<style lang="scss">
....
</style>
I get the following error:
Error: Error while preprocessing /Users/francesco.leardini/Documents/pet projects/budget-tracker/src/routes/+page.svelte - Preprocessor dependency "sass" not found. Did you install it?
at loadPreprocessor (file:///Users/francesco.leardini/Documents/pet%20projects/budget-tracker/node_modules/vite/dist/node/chunks/dep-5e7f419b.js:36922:19)
at scss (file:///Users/francesco.leardini/Documents/pet%20projects/budget-tracker/node_modules/vite/dist/node/chunks/dep-5e7f419b.js:36962:20)
at compileCSS (file:///Users/francesco.leardini/Documents/pet%20projects/budget-tracker/node_modules/vite/dist/node/chunks/dep-5e7f419b.js:36482:40)
at async preprocessCSS (file:///Users/francesco.leardini/Documents/pet%20projects/budget-tracker/node_modules/vite/dist/node/chunks/dep-5e7f419b.js:36644:12)
at async style (file:///Users/francesco.leardini/Documents/pet%20projects/budget-tracker/node_modules/#sveltejs/vite-plugin-svelte/dist/index.js:2055:20)
at async process_single_tag (file:///Users/francesco.leardini/Documents/pet%20projects/budget-tracker/node_modules/svelte/compiler.mjs:46844:27)
at async Promise.all (index 0)
at async replace_in_code (file:///Users/francesco.leardini/Documents/pet%20projects/budget-tracker/node_modules/svelte/compiler.mjs:46732:26)
at async process_tag (file:///Users/francesco.leardini/Documents/pet%20projects/budget-tracker/node_modules/svelte/compiler.mjs:46858:29)
at async preprocess (file:///Users/francesco.leardini/Documents/pet%20projects/budget-tracker/node_modules/svelte/compiler.mjs:46898:30)
Shouldn't scss files be handled out of the box as stated in the docs?

Add the dependency sass to your project first?
npm add -D sass or with whatever package manager you use.

Related

Cache transformed node modules with vite/esbuild

vite build uses esbuild to transform both the package dependencies (node modules) as well as the app source code into the target JavaScript specification, i.e. es2015.
I observe that vite/esbuild re-transform the entire sources in ./node_modules every time vite build is run.
How can this build stack be used to keep and reuse the previously transformed files, at least for the entire ./node_modules folder (given dependencies didn't change of course) so that subsequent vite build command invocations run significantly faster?
One way to improve the performance of subsequent Vite build command invocations is by using a caching mechanism. You can use a caching tool such as cache-loader or hard-source-webpack-plugin to cache the transpilation results of the node modules.
This will allow Vite to reuse the previously transpiled files for the node modules, as long as the dependencies haven't changed.
This can greatly speed up the build process.
You can also try to configure esbuild to only transpile the changed files instead of the entire codebase using the -w or --watch option when running the esbuild command. This option tells esbuild to watch the input files and only transpile the files that have been modified.
In Vite, you can configure the esbuild plugin to use the --watch option by adding the following to your vite.config.js file:
const esbuildConfig = {
watch: true,
};
module.exports = {
esbuild: esbuildConfig,
};
Examples :
cache-loader:
Install the package:
npm install cache-loader --save-dev
In your vite.config.js file, configure the cache-loader to be used for transpiling the node modules by adding it as a rule in the build object:
module.exports = {
build: {
...
css: {
...
},
js: {
...
loaderOptions: {
cache: true,
cacheDirectory: 'node_modules/.cache'
}
},
...
}
}
Run your build command ( vite build )
hard-source-webpack-plugin:
install the package:
npm install hard-source-webpack-plugin --save-dev
In your vite.config.js file, import the plugin and add it to the build.plugins array:
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
module.exports = {
build: {
...
plugins: [
new HardSourceWebpackPlugin()
],
...
}
}
Run your build command (vite build)
These examples, as you asked in your comment, are for Vite versions 2.5.8 and 3.x. However, in order to use them with Vite 3.x you need to update the build config to match the new format.
Please don't hesitate to write a comment if you still have a problem or questions!

webpack to allow import of all sass files? i.e #import 'components/**/*'

I'm currently using css-loader, node-sass, sass-loader and style-loader packages within webpack to compile my sass files, here is how my loader looks at the moment:
{
test: /\.scss$/,
loader: 'style!css!sass'
}
I want to use folder structure like this for my styles
styles
components/
main.sass
and somehow within main.sass I want to import everything from components folder so something like #import './components/**/*' is this possible via webpack?
You can prefix a Sass import with '~' to tell the Sass loader to use webpack's require() resolution on the import. Once webpack is in charge of the import you have some flexibility.
If you do a dynamic require, e.g. require('~./components/' + someVar + '.scss'), webpack can't evaluate the variable at build time and it bundles all the possible files in that directory, and the actual resolution of the require() happens at runtime (which can lead to errors at runtime if you've asked for something that doesn't exist). Not sure off the top of my head if that would give you what you need (all the files bundled) or if you would still need to explicitly require() each partial -- but if that's the case you could easily loop through all the files in the directory and require each one.
More on how you can leverage webpack's dynamic requires and loading context.

gulp, wiredep and custom sass file

So I made a library that I can bower install using a direct link. I can use this library from another internal application by adding the library name in the dependency of the bower.json file. When other internal application does a bower update, the changes I made on the library will be applied to their application. This part is working very well.
Now, I'd like the other software devs to have freedom to change the styles. They can create css file directly and that will work. However, it's a hackish route. I can provide them the same settings file that I use.
So i tried putting that file in the main section of the bower.json but wiredep is processing it. I put it in exclude and the error is gone when I run gulp.
"main": [
"dist/stylesheet.css",
"src/_settings.scss"
],
this is the code that prevented it from being parsed by wiredep
wiredep: {
directory: 'bower_components',
exclude: ['css/foundation.css','src/_settings.scss']
}
Am I right that I'll have to create a new gulp task and put 'src/_settings.scss' as gulp.src like this
gulp.task('sasstask2', function () {
return gulp.src('src/_settings.scss')
.pipe($.sass())
.pipe(gulp.dest('src/css'));
});
I also like the generate css to be injected to index.html but not sure how to do it? Will wiredep automatically inject it to index.html?

Angular generator without Ruby

The angular generator has a dependency on compass and thus ruby when using SASS.
Two questions:
Is it possible/practical to remove the ruby dependency by using something like node-sass?
If so, how do I accomplish #1 and still use angular generator to generate controllers, routes, services, etc in the future?
If you are using the Yeoman Angular generator and you wish to use SASS/SCSS without depending on Ruby, you could use the grunt-sass Grunt module.
Yeoman is essentially a project set-up with Grunt so you can just add whichever Grunt modules you need. If you are unfamiliar with Grunt, you can read the documentation here.
Essentially, you can set up the Grunt configuration for your SASS task, then register the task in your generated project's Gruntfile.js:
grunt.initConfig({
sass: {
options: {
sourceMap: true
},
dist: {
files: {
'main.css': 'main.scss'
}
}
}
});
grunt.registerTask('default', ['sass']);
You should note that this Grunt module uses Node SASS for CSS compilation instead of Compass, so you may be missing out on some Compass mixins you may be used to.

How can Modernizr 3.x modules be required?

I am trying to require specific Modernizr tests into a browserify project but i must be doing something wrong.
I use the deamdify transform when building using browserify.
Modernizr is required as an NPM package directly from the source repo's master. The reason this happens is because pending v3.x will be available through npm and the latest bower packages do not offer the sources, only prebuilt versions.
I want to be flexible with what Modernizr modules i include in my application so for my needs, having an extra build-modernizr step is not acceptable. I want to have a single build step, browserify.
The problem is that deamdify fails to recognize the required Moderizr modules as AMD and does not resolve their dependencies or wrap them in AMD containers...
I have setup a repo that illustrates the problem:
https://github.com/thanpolas/browserify-modernizr
Nope, you aren't doing anything wrong. Its just not set up to work like that quite yet. Its a bit of a custom AMD.
#robw has been working on a new build system that I believe would show you to do what you are looking for.
update: the new build system is finally in effect - using master as of 2/8/2015 you can require tests
Though you said that having an extra build-modernizr step is not acceptable for you (I provided answer for that case) but still I want to add another answer for the case when using browserify and Modernizr with gulp.
gulp-modernizr can crawl through specified files, find Modernizr usages and make custom Modernizr build:
npm install --save-dev gulp-modernizr
Define gulp task in gulpfile.js:
var modernizr = require('gulp-modernizr')
gulp.task('modernizr', function () {
return gulp.src('src/**/*.js')
.pipe(modernizr())
.pipe(gulp.dest('build'));
});
This task generates build/modernizr.js that contains only tests used in your source code. When added to html file with <script> tag this file sets Modernizr instance to window.Modernizr property. So you can use it like:
if (window.Modernizr.filereader) {
// your code here
}
Using modernizr as module.
If you want to use modernizr as module (see this issue for discussion) than create src/modernizr.js file:
module.exports = window.Modernizr;
And expose this file as module with name modernizr:
var browserify = require('browserify');
var source = require('vinyl-source-stream');
gulp.task('browserify', ['modernizr'], function() {
var b = browserify({ entries: 'src/index.js' });
b.require('src/modernizr.js', {expose: 'modernizr'});
return b.bundle()
.pipe(source('index.js'))
.pipe(gulp.dest('build'));
});
Now you can use it in your source code:
var modernizr = require('modernizr');
if (modernizr.filereader) {
...
}
Injecting build/modernizr.js and build/index.js scripts in index.html.
Suppose you have src/index.html:
<!DOCTYPE html>
<html class='no-js' lang=''>
<head>
<meta charset='UTF-8'>
<title>Example</title>
<!-- inject:head:js -->
<!-- endinject -->
</head>
<body>
<!-- inject:js -->
<!-- endinject -->
</body>
</html>
The following gulp task will inject build/modernizr.js in head section and build/index.js in body section and place resulting file to build/index.html:
var inject = require('gulp-inject');
gulp.task('html', ['browserify'], function() {
return gulp.src('src/index.html')
.pipe(inject(gulp.src('build/modernizr.js', { read: false }),
{ ignorePath: 'build', addRootSlash: true, starttag: '<!-- inject:head:{{ext}} -->'}))
.pipe(inject(gulp.src('build/index.js', { read: false }),
{ ignorePath: 'build', addRootSlash: true}))
.pipe(gulp.dest('build'));
});
With browsernizr you can specify what tests you need in your source code.
Install:
npm install --save browsernizr
Use:
// pick what tests you need
require('browsernizr/test/css/rgba');
require('browsernizr/test/file/filesystem');
require('browsernizr/test/websockets');
// make sure to do this after importing the tests
require('browsernizr');
// or if you need access to the modernizr instance:
var Modernizr = require('browsernizr');
browserify will include required tests in bundle.

Resources