Using SASS (indented syntax) in storybook - vue.js

I am facing problems using SASS by it's indented syntax, since the documentation is only describing a way to configure storybook for sassy css syntax (which I don't want to use) - is there also a workaround for using the original SASS Syntax instead? I looked around the internet and could not find any information about that issue...
My current webpack/main.js config is looking like this (not working):
const path = require('path');
module.exports = {
stories: ['../stories/**/*.stories.js'],
addons: ['#storybook/addon-actions', '#storybook/addon-links'],
webpackFinal: async (config, { configType }) => {
config.module.rules.push({
test: /\.sass$/,
use: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
indentedSyntax: true,
sassOptions: {
indentedSyntax: true
}
}
}
],
include: path.resolve(__dirname, '../'),
});
return config;
},
};

Got it solved!
The problem was a conflict accured throught suing "indentedSyntax: true," which should only be used fpr older sass-loader versions (<8). Since I am using 8.x "indentedSyntax: true," should be placed within the sassOptions object...
Anyways, since I did not found any information related to that topic I will post the solution in here: Just add the webpack configuration to your .storybook/main.js, so you can use SASS within your storybook.
const path = require('path');
module.exports = {
stories: ['../stories/**/*.stories.js'],
addons: ['#storybook/addon-actions', '#storybook/addon-links'],
webpackFinal: async (config, { configType }) => {
config.module.rules.push({
test: /\.sass$/,
use: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
sassOptions: {
indentedSyntax: true
}
}
}
],
include: path.resolve(__dirname, '../'),
});
return config;
},
};

Related

How to convert existing webpack code to chainWebpack?

I write Vue2 app using Vuetify2. I need to add sass-loader to webpack as per docs: https://vuetifyjs.com/en/getting-started/installation/#webpack-install
So I need to edit webpack and want to do this using chainWebpack. According to docs I can do it in vue.config.js. The issue is that I don't know how to properly 'convert' regular webpack snippet to chaining. I need to chain this:
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.s(c|a)ss$/,
use: [
'vue-style-loader',
'css-loader',
{
loader: 'sass-loader',
// Requires sass-loader#^7.0.0
options: {
implementation: require('sass'),
indentedSyntax: true // optional
},
// Requires >= sass-loader#^8.0.0
options: {
implementation: require('sass'),
sassOptions: {
indentedSyntax: true // optional
},
},
},
],
},
],
}
}
and this is my vue.config.js file where I tried to use chainWebpack (note that transpileDependencies was in this file before, I don't touch it and it must be here):
const { defineConfig } = require('#vue/cli-service')
module.exports = defineConfig({
transpileDependencies: [
'vuetify'
],
chainWebpack: config => {
config.module
.rule('sass')
.test(/\.s(c|a)ss$/)
.use('vue-style-loader','css-loader',)
.loader('sass-loader')
.tap(options => {
implementation: require('sass'),
sassOptions: {
indentedSyntax: true // optional
}
return options
})
}
})
However it doesn't work.

Storybook: Unable to override vuetify sass variables using variables.scss

I have created some custom components on top of vuetify components. In order to match my design I have overridden the vuetify sass variables by creating a .scss file in path src/scss/variables.scss and written custom .scss as well. This works absolutely fine but when I try to import the components in my storybook I am unable to see the overridden design.
// .storybook/main.js
const path = require("path");
module.exports = {
stories: [
// "../src/**/*.stories.mdx",
"../src/**/*.stories.#(js|jsx|ts|tsx)"
],
addons: [
"#storybook/addon-links",
{
name: "#storybook/addon-essentials",
options: {
docs: true
}
}
],
webpackFinal: async (config, { configType }) => {
config.resolve.alias["~storybook"] = path.resolve(__dirname);
config.resolve.alias["#"] = path.resolve(__dirname, "..", "src");
config.module.rules.push({
test: /\.s(c|a)ss$/,
use: [
"style-loader",
"css-loader",
{
loader: "sass-loader",
options: {
implementation: require("sass")
prependData: "#import '#/scss/variables.scss';", // ISSUE IS HERE
sassOptions: {
indentedSyntax: false // Tried with both true and false
},
}
}
],
include: path.resolve(__dirname, "../")
});
return config;
}
};

storybook vue sass additionalData not working

In my vue.config.js file contains (ref: https://austingil.com/global-sass-vue-project/):
css: {
loaderOptions: {
sass: {
additionalData: `
#import "#/storybook-components/src/styles/utils/_variables.scss";
#import "#/storybook-components/src/styles/utils/_shadowMixins.scss";
`,
implementation: require('sass')
}
}
},
This allows me to use the sass variables within the vue components.
We have a central and shared storybook library for common components that was working perfectly, but now we share the variables it fails.
How can I share add the additionalData to the vue components in storybook? There is a vue.config file in the storybook project but I don't think it is being read...
The .storybook/main.js looks like (following the guides):
const path = require('path');
// Export a function. Accept the base config as the only param.
module.exports = {
webpackFinal: async (config, { configType }) => {
// `configType` has a value of 'DEVELOPMENT' or 'PRODUCTION'
// You can change the configuration based on that.
// 'PRODUCTION' is used when building the static version of storybook.
// Make whatever fine-grained changes you need
config.module.rules.push({
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
include: path.resolve(__dirname, '../'),
});
// Return the altered config
return config;
},
typescript: {
check: false,
checkOptions: {},
reactDocgen: 'react-docgen-typescript',
reactDocgenTypescriptOptions: {
shouldExtractLiteralValuesFromEnum: true,
propFilter: (prop) => (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true),
},
},
"stories": [
"../src/**/*.stories.mdx",
"../src/**/*.stories.#(js|jsx|ts|tsx)"
],
"addons": [
"#storybook/addon-links",
"#storybook/addon-essentials"
],
"framework": "#storybook/vue"
};
So I assume the additionalData is meant to be added to the webpack final section, I just cannot see how?
As usual.. the rubber duck affect kicked in after posting the question. This was a very annoying one to resolve.
The following config worked for me, note the expansion of the rule for the sass-loader.
Additional note: webpack was fixed in the dev deps to "webpack":"^4.46.0"
const path = require('path');
// Export a function. Accept the base config as the only param.
module.exports = {
webpackFinal: async (config, { configType }) => {
// `configType` has a value of 'DEVELOPMENT' or 'PRODUCTION'
// You can change the configuration based on that.
// 'PRODUCTION' is used when building the static version of storybook.
// Make whatever fine-grained changes you need
config.module.rules.push({
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
{
// Compiles Sass to CSS
loader: "sass-loader",
options: {
additionalData: `
#import "./src/styles/utils/_variables.scss";
#import "./src/styles/utils/_shadowMixins.scss";
`,
implementation: require('sass'),
},
},
],
include: path.resolve(__dirname, '../'),
});
// Return the altered config
return config;
},
typescript: {
check: false,
checkOptions: {},
reactDocgen: 'react-docgen-typescript',
reactDocgenTypescriptOptions: {
shouldExtractLiteralValuesFromEnum: true,
propFilter: (prop) => (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true),
},
},
"stories": [
"../src/**/*.stories.mdx",
"../src/**/*.stories.#(js|jsx|ts|tsx)"
],
"addons": [
"#storybook/addon-links",
"#storybook/addon-essentials"
],
"framework": "#storybook/vue"
};

Sapper/Svelte SASS preprocessing?

So I was checking out the realworld implementation of Sapper/Svelte: https://github.com/sveltejs/realworld
I've read a lot about SASS preprocessing, and it doesn't seem like it is fully supported, but there are some docs on it. From what I could put together, I should be able to preprocess my tags after I made the following modifications to my webpack.client.config.js file:
const svelte = require('rollup-plugin-svelte');
const sass = require('svelte-preprocess-sass').sass;
const config = require('sapper/webpack/config.js');
const webpack = require('webpack');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
entry: config.client.entry(),
output: config.client.output(),
resolve: {
extensions: ['.js', '.html']
},
module: {
rules: [
{
test: /\.html$/,
exclude: /node_modules/,
use: {
loader: 'svelte-loader',
options: {
hydratable: true,
emitCss: !config.dev,
cascade: false,
store: true
}
}
},
config.dev && {
test: /\.css$/,
use: [
{ loader: "style-loader" },
{ loader: "css-loader" }
]
},
!config.dev && {
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [{ loader: 'css-loader', options: { sourceMap: config.dev } }]
})
}
].filter(Boolean)
},
plugins: [
svelte({
preprocess: {
style: sass(),
}
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'main',
async: true,
children: true
}),
config.dev && new webpack.HotModuleReplacementPlugin(),
!config.dev && new ExtractTextPlugin('main.css'),
!config.dev && new webpack.optimize.ModuleConcatenationPlugin(),
!config.dev && new UglifyJSPlugin(),
].filter(Boolean),
devtool: config.dev ? 'inline-source-map' : false
};
I keep getting the following error:
node server.js
realworldsapper/node_modules/tapable/lib/Tapable.js:375
arguments[i].apply(this);
Any ideas on how to fix this?
You're mixing and matching Rollup and webpack, which are two different module bundlers — you're adding rollup-plugin-svelte to a webpack config, and webpack doesn't know what to do with it so it throws an error.
Instead, use svelte-preprocess-sass inside the svelte-loader config:
use: {
loader: 'svelte-loader',
options: {
hydratable: true,
emitCss: !config.dev,
cascade: false,
store: true,
style: sass()
}
}
(Note that the style: sass() line will become preprocess: { style: sass() } in a future version of svelte-loader — see this issue).
By the way, it looks like you're using an older version of Sapper — there have been some major improvements recently, so it's worth upgrading to 0.9. Unfortunately it does mean making some changes to your project structure (see the migration guide for the details, or reclone sapper-template and copy your routes folder over).
You should add exclude: /node_modules/ to each of your rules:
test: /\.css$/,
exclude: /node_modules/, // <- Add this
This ensures that transpilation is not applied to any of the files in the node_modules folder.

Webpack with babel-loader not emitting valid es5

I have a webpack config that is based off https://github.com/vuejs-templates/webpack-simple/blob/master/template/webpack.config.js
It uses vue-loader and babel-loader. The issue is I cannot get it to generate ES5 code so that it will work in the most broad range of clients.
If I use the ES2015 preset, webpack.optimize.UglifyJsPlugin fails to minify the output because Uglify can only handle ES5 (not counting the harmony branch). The errors are similar to: Unexpected token: punc (() and occur in multiple files.
I can work around this by using babili-webpack-plugin which will minify the ES6 code but is very slow. However, when I deploy this code, I see errors being reported back saying Block-scoped declarations (let, const, function, class) not yet supported outside strict mode so I know they are older clients choking on ES6 code.
How can I get proper ES5 code output from babel-loader? I have tried multiple presets, with or without the transform-runtime plugin. Config below:
const webpack = require('webpack');
const globEntries = require('webpack-glob-entries');
const _ = require('lodash');
const path = require('path');
const BabiliPlugin = require("babili-webpack-plugin");
const env = process.env.NODE_ENV;
let entries;
if (env === 'production') {
entries = globEntries('./src/**/vue/*.js');
} else {
entries = _.mapValues(globEntries('./src/**/vue/*.js'), entry => [entry, 'webpack-hot-middleware/client?reload=true']);
}
module.exports = {
entry: entries,
output: {
path: '/', ///no real path is required, just pass "/"
publicPath: '/vue',
filename: '[name].js',
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
scss: 'vue-style-loader!css-loader!sass-loader',
sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax',
},
// other vue-loader options go here
},
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
query: {
presets: ['es2015'],
plugins: ['transform-runtime'],
},
},
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]',
},
},
],
},
resolve: {
alias: {
vue$: 'vue/dist/vue.esm.js',
},
},
plugins: [
new webpack.HotModuleReplacementPlugin(), // Enable HMR
new webpack.NoEmitOnErrorsPlugin(),
],
performance: {
hints: false,
},
devtool: '#eval-source-map',
};
if (env === 'staging' || env === 'production') {
//module.exports.devtool = env === 'staging' ? '#source-map' : false;
module.exports.devtool = '#source-map';
module.exports.output.path = path.resolve(__dirname, './src/v1/parse/cloud/public/vue');
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: `"${env}"`,
},
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false,
},
}),
// new BabiliPlugin(),
new webpack.LoaderOptionsPlugin({
minimize: true,
}),
]);
}
vue-loader will process your js with babel-loader (if it's detected), and uses .babelrc by default.
In your current setup you are not passing any options to Babel when it is used by vue-loader (meaning Babel uses no rules for your Vue files).
Either create .babelrc or specify the js loader by yourself for the .vue files to provide it with options:
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
js: 'babel?presets[]=es2015' // Pass parameters as options
}
}
}
The env preset for Babel has an uglify option that will fully compile to ES5. This preset is recommended practice to keep your environment up to date.
// .babelrc
{
"presets": [
[ "env", { "uglify": true } ],
"stage-1" // Or other presets not included with 'env' preset.
],
"plugins": ["transform-runtime"]
}
Instead of using preset es2015 only, you might add es2016 and es2017, as well as stage-4, stage-3, etc. to assure all your code is transformed, and not just the ES2015 parts.
Nothing wrong with answer here already, but here is a solution that does not require a .babelrc file. This answer works for a standalone webpack.config.js file. I got this answer from taking a look under the hood of the laravel-mix library.
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders:{
js: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
presets: [
['env', {
'modules': false,
'targets': {
'browsers': ['> 2%'],
uglify: true
}
}]
],
plugins: [
'transform-object-rest-spread',
['transform-runtime', {
'polyfill': false,
'helpers': false
}]
]
}
},
}
}
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
},
I spent the better part of a day reading up all these useless blogs omit the core concept that babel-loader has to be attached to the vue-loader.