Recently, I began experimenting with Vue and encountered an issue related to using aliases for importing files in Storybook:
In my project, there is a SvgIcon component:
<template>
<div>
props from the icon: {{this.$props}}
<svg v-if="icon" class="svg-icon">
<title v-if="title">{{ title }}</title>
<use v-bind="{ 'xmlns:xlink':'http://www.w3.org/1999/xlink', 'xlink:href': icon }"></use>
</svg>
<img v-else-if="image" :src="image" class="image-icon"/>
</div>
</template>
<script>
export default {
name: 'SvgIcon',
data: function() {
return {
icon: null,
image: null
}
},
props: {
title: {
type: String,
default: ''
},
iconFallback: {
type: String,
required: false
},
iconId: {
type: String,
required: true,
validator(iconName) {
if (!iconName) {
console.warn('icon can not be empty')
return false
}
return true
}
}
},
watch: {
iconId: {
immediate: true,
handler(iconId) {
iconId && import(`@/assets/icons/${iconId}.svg`)
.then(svg => {
// debugger
console.log(this, 'this from SvgIcon')
if (Object.prototype.hasOwnProperty.call(svg, 'default')) {
this.icon = svg.default
} else {
this.icon = svg
}
}).catch(() => {
this.image = this.iconFallback && require(`@/assets/icons/${this.iconFallback}.png`)
})
}
}
}
}
</script>
<style scoped lang="scss">
svg {
width: 32px;
height: 32px;
vertical-align: middle;
&.icon-status {
width: 14px;
height: 14px;
min-width: 14px;
transform: translateY(-6%);
fill: $light-orange;
}
&.icon-size-small {
width: 14px;
height: 14px;
}
&.icon-size-medium {
width: 18px;
height: 18px;
}
@include only_mini {
@include skip_element;
}
}
</style>
The component imports another file using the @
alias:
import(`@/assets/icons/${iconId}.svg`)
This setup works well on localhost:3000, but when running Storybook on port 6006, it throws the following error:
ERROR in ./src/js/globalComponents/SvgIcon.vue?vue&type=script&lang=js& (./node_modules/babel-loader/lib??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/js/globalComponents/SvgIcon.vue?vue&type=script&lang=js&)
Module not found: Error: Can't resolve '@/assets/icons' in 'src/js/globalComponents'
ERROR in ./src/js/globalComponents/SvgIcon.vue?vue&type=script&lang=js& (./node_modules/babel-loader/lib??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/js/globalComponents/SvgIcon.vue?vue&type=script&lang=js&)
Module not found: Error: Can't resolve '@/assets/icons' in 'src/js/globalComponents'
The alias is defined in vue.config.js
at the root of the project:
configureWebpack: {
resolve: {
alias: require('./aliases.config').webpack
},
...
}
This configuration references the file ./aliases.config
:
const path = require('path')
function resolveSrc(_path) {
return path.join(__dirname, _path)
}
const aliases = {
'@': 'src',
'@src': 'src'
}
module.exports = {
webpack: {},
jest: {}
}
for (const alias in aliases) {
module.exports.webpack[alias] = resolveSrc(aliases[alias])
module.exports.jest['^' + alias + '/(.*)$'] =
'<rootDir>/' + aliases[alias] + '/$1'
}
Additionally, here's the Storybook configuration in .storybook/main.js
:
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: /\.scss$/,
use: ['style-loader', 'css-loader',
{
loader: 'sass-loader',
options: {
prependData: `@import "src/project/test/vars.scss"; @import "src/project/common/mixins.scss"; @import "src/styles/styles.scss";`
}
}
],
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': path.dirname(path.resolve(__dirname, "../src")),
},
},
include: path.resolve(__dirname, '../'),
});
return config;
},
};
If anyone can identify where I may be going wrong, your insights would be greatly appreciated.