I've just started a fresh rails-6 project with webpacker and vue. I wanted to have the vue-component styles in sass, but the sass-loader throughs:
Error: Module build failed (from ./node_modules/sass-loader/dist/cjs.js) SassError: Invalid CSS after "": expected 1 selector or at-rule, was ".foo"
Has anyone seen this before? Or maybe, how can I debug what goes wrong here?
foo.vue
<template>...</template>
<script>...</script>
<style lang="sass">
.foo
margin: 0
padding: 0
</style>
Removing the initial indention of the sass
code does not help.
rails new --database=postgresql --skip-test foo
rails webpacker:install:vue
yarn add vue-turbolinks
rails webpacker:install:coffee
yarn add coffee-loader@1
yarn add sass-loader@10
{
"name": "foo",
"private": true,
"dependencies": {
"@popperjs/core": "^2.9.2",
"@rails/actioncable": "^6.0.0",
"@rails/activestorage": "^6.0.0",
"@rails/ujs": "^6.0.0",
"@rails/webpacker": "5.2.1",
"@tabler/core": "tabler/tabler",
"bootstrap": "^5.0.0-beta3",
"coffee-loader": "1",
"coffeescript": "1.12.7",
"sass-loader": "10",
"tabler": "^1.0.0-alpha.8",
"turbolinks": "^5.2.0",
"vue": "^2.6.12",
"vue-loader": "^15.9.6",
"vue-select": "^3.11.2",
"vue-template-compiler": "^2.6.12",
"vue-turbolinks": "^2.2.2"
},
"version": "0.1.0",
"devDependencies": {
"webpack-dev-server": "^3.11.2"
}
}
I've also added vue-select
, bootstrap
, and tabler
. But I don't think they will interfere.
config/webpack/environment.js
const { environment } = require('@rails/webpacker')
const coffee = require('./loaders/coffee')
const { VueLoaderPlugin } = require('vue-loader')
const vue = require('./loaders/vue')
environment.plugins.prepend('VueLoaderPlugin', new VueLoaderPlugin())
environment.loaders.prepend('vue', vue)
environment.loaders.prepend('coffee', coffee)
module.exports = environment
application.html.haml
!!!
%html
%head
%title Foo
= csrf_meta_tags
= csp_meta_tag
= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'
= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload'
%body
#vue_app
= yield
packs/application.js
import Rails from "@rails/ujs"
import Turbolinks from "turbolinks"
import * as ActiveStorage from "@rails/activestorage"
import "channels"
Rails.start()
Turbolinks.start()
ActiveStorage.start()
import 'bootstrap'
import '@tabler/core'
import TurbolinksAdapter from 'vue-turbolinks'
import Vue from 'vue/dist/vue.esm'
Vue.use(TurbolinksAdapter)
document.addEventListener('turbolinks:load', () => {
const app = new Vue({
el: '#vue_app',
data: () => {
return {}
},
components: {}
})
})
There are two syntax variants:
There are two syntaxes available for Sass. The first, known as
SCSS (Sassy CSS)
and used throughout this reference, is an extension of the syntax of CSS. This means that every valid CSS stylesheet is a valid SCSS file with the same meaning. This syntax is enhanced with the Sass features described below. Files using this syntax have the .scss extension.The second and older syntax, known as the
indented syntax (or sometimes just “Sass”)
, provides a more concise way of writing CSS. It uses indentation rather than brackets to indicate nesting of selectors, and newlines rather than semicolons to separate properties. Files using this syntax have the .sass extension.
See also: https://stackoverflow.com/a/5654471/2066546, https://sass-lang.com/documentation/syntax
sass-loader
use?The sass-loader chooses the syntax according to the file extension by default:
The
indentedSyntax
option hastrue
value for thesass
extension.
This means that the original sass syntax (indented syntax) is only used if the file extension is .sass
. Within the vue component, which has the extension .vue
, the sass-loader
uses the newer "scss" syntax by default.
sass-loader
to use the sass syntax (indented syntax)?The sass-loader documentation has instructions on how to specify indentedSyntax: true
in the webpack configuration.
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
"style-loader",
"css-loader",
{
loader: "sass-loader",
options: {
sassOptions: {
indentedSyntax: true
},
},
},
],
},
],
},
};
However, with webpacker, the webpack configuration is composed automatically. So, one needs to modify the existing configuration object:
// config/webpack/environment.js
const { environment } = require('@rails/webpacker')
// To get an overview, have a look at `environment.loaders`.
console.log(environment.loaders)
const { merge } = require('webpack-merge')
const sassConfig = environment.loaders.find(el => el.key == 'sass')
const sassLoader = sassConfig.value.use.find(el => el.loader == 'sass-loader')
sassLoader.options = merge(sassLoader.options, {
sassOptions: {
indentedSyntax: true
}
})
module.exports = environment
This requires webpack-merge: yarn add webpack-merge
.
I'm sure there are better ways to do it. Please feel free to add answers or comments!