rollup treeshaking doesn't work if any unused function has external dependency - rollup

// file1.js
import styled from "styled-components";
export const myDiv = styled.div``;
export const myLabel = styled.label``;
// input.js --> Rollup input file to bundle
import {myDiv} from "./file1"
export {myDiv};
Ideally myLabel should not be bundled as its not imported as per treeshaking. But bundle includes both myDiv and myLabel.
Please help me with understanding.

i resolved the issue by adding { modules: false } on the babel loader preset
{
loader: 'babel-loader',
options: {
presets: [ ["#babel/preset-env", { modules: false }] ],
}
}

Related

How to mock SVG's when snapshot testing with vitest and Storybook?

I am trying to run vitest snapshot tests on Storybook stories using the composeStories Fn from #storybook/testing-react, but I keep getting the error:
FAIL src/components/common/Nav/Nav.test.tsx > Nav Component > it should match the snapshot
Error: Element type is invalid: expected a string (for built-in components) or a class/function
(for composite components) but got: undefined. You likely forgot to export your component from
the file it's defined in, or you might have mixed up default and named imports.
Check the render method of `Nav`.
//... stack trace
I believe it's related to the svg imports, as this only occurs in components that import svgs as react components via the SVGR library. i.e.
// components/common/Nav.tsx
import { ReactComponent as ECDLogo } from '#assets/ecd_logo.svg';
And my vite.config.ts uses the vite-svgr-plugin:
// vite.config.ts
import { defineConfig } from 'vite';
import react from '#vitejs/plugin-react';
import svgr from 'vite-plugin-svgr';
import tsconfigPaths from 'vite-tsconfig-paths';
import path from 'path';
const tsConfigPathsOpts = {
extensions: ['.svg', '.png', '.jpeg'],
loose: true,
};
export default defineConfig({
build: {
outDir: 'build',
},
define: {
global: {},
},
resolve: {
alias: {
'#': path.resolve(__dirname, './src'),
'#assets': path.resolve(__dirname, './src/assets'),
'#styles': path.resolve(__dirname, './src/styles'),
'#types': path.resolve(__dirname, './src/types'),
'#components': path.resolve(__dirname, './src/components'),
},
},
plugins: [react(), svgr(), tsconfigPaths(tsConfigPathsOpts)],
});
My Storybook config (.storybook/main.js) looks like so:
const path = require('path');
const { mergeConfig } = require('vite');
const tsconfigPaths = require('vite-tsconfig-paths');
const svgr = require('vite-plugin-svgr');
const tsConfigPathsOpts = {
extensions: ['.svg', '.png', '.jpeg'],
loose: true,
};
module.exports = {
stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.#(js|jsx|ts|tsx)'],
addons: [
'#storybook/addon-essentials',
'#storybook/preset-create-react-app',
'#storybook/addon-a11y',
'#storybook/node-logger',
'storybook-addon-designs',
'storybook-color-picker',
'storybook-dark-mode',
],
framework: '#storybook/react',
core: {
builder: '#storybook/builder-vite',
},
async viteFinal(config, { configType }) {
return mergeConfig(config, {
resolve: {
alias: {
'#': path.resolve(__dirname, '../src'),
'#assets': path.resolve(__dirname, '../src/assets'),
'#styles': path.resolve(__dirname, '../src/styles'),
'#types': path.resolve(__dirname, '../src/types'),
'#components': path.resolve(__dirname, '../src/components'),
},
},
plugins: [svgr(), tsconfigPaths.default(tsConfigPathsOpts)],
});
},
};
I've come to understand that I need to mock these SVG's so that their snapshot is consistent, but I need direction on whether my mocking implementation is correct. See the vi.mock Fn below.
// components/common/Nav/Nav.test.tsx
import React from 'react';
import { render } from '#testing-library/react';
import '#testing-library/jest-dom/extend-expect';
import { composeStories } from '#storybook/testing-react';
import * as stories from './Nav.stories'; // import all stories from the stories file
import { vi } from 'vitest';
const { NavDefault } = composeStories(stories);
👀
vi.mock('#assets/*', () => {
return {
default: 'SVGUrl',
ReactComponent: 'div',
};
});
describe('Nav Component', () => {
test('it should match the snapshot', () => {
const { asFragment } = render(<NavDefault />);
expect(asFragment()).toMatchSnapshot();
});
});
I was expecting this to mock all the imports from #assets/* to be strings "SVGUrl" or 'div'
But I get the same error as above:
FAIL src/components/common/Nav/Nav.test.tsx > Nav Component > it should match the snapshot
Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
we had the same issue today and fixed it by adding the plugin svgr() in vitest.config.ts
import svgr from "vite-plugin-svgr";
export default defineConfig({
plugins: [
// ...other plugins
svgr(),
]
})

Using vue slots in library gives currentRenderingInstance is null

I am creating a Vue component library with Rollup, but when I use slots it gives me the following error:
Uncaught (in promise) TypeError: currentRenderingInstance is null
I made a very simple component in my library:
<script setup></script>
<template>
<button>
<slot></slot>
</button>
</template>
<style scoped></style>
Then I simply use it like this:
<ExampleComponent>
Text
</ExampleComponent>
If I remove the slot and replace it with a prop or hard-coded text, everything works fine.
This is my rollup.config.js:
import { defineConfig } from 'rollup';
import path from 'path';
import resolve from '#rollup/plugin-node-resolve';
import commonjs from '#rollup/plugin-commonjs';
import postcss from 'rollup-plugin-postcss';
import vue from 'rollup-plugin-vue';
// the base configuration
const baseConfig = {
input: 'src/entry.js',
};
// plugins
const plugins = [
vue(),
resolve({
extensions: ['.js', '.jsx', '.ts', '.tsx', '.vue'],
}),
// process only `<style module>` blocks.
postcss({
modules: {
generateScopedName: '[local]___[hash:base64:5]',
},
include: /&module=.*\.css$/,
}),
// process all `<style>` blocks except `<style module>`.
postcss({ include: /(?<!&module=.*)\.css$/ }),
commonjs(),
];
const external = ['vue'];
const globals = {
vue: 'Vue',
};
export default [
// esm
defineConfig({
...baseConfig,
input: 'src/entry.esm.js',
external,
output: {
file: 'dist/vue-my-lib.esm.js',
format: 'esm',
exports: 'named',
},
plugins,
}),
// cjs
defineConfig({
...baseConfig,
external,
output: {
compact: true,
file: 'dist/vue-my-lib.ssr.js',
format: 'cjs',
name: 'VueMyLib',
exports: 'auto',
globals,
},
plugins,
}),
// iife
defineConfig({
...baseConfig,
external,
output: {
compact: true,
file: 'dist/vue-my-lib.min.js',
format: 'iife',
name: 'VueMyLib',
exports: 'auto',
globals,
},
plugins,
}),
];
Any idea about the problem?
After a whole day of searching, I found the solution (here and here). It's a problem with using a library locally (e.g., through npm link) where it seems there are two instances of Vue at the same time (one of the project and one of the library). So, the solution is to tell the project to use specifically its own vue through webpack.
In my case, I use Jetstream + Inertia, so I edited webpack.mix.js:
const path = require('path');
// ...
mix.webpackConfig({
resolve: {
symlinks: false,
alias: {
vue: path.resolve("./node_modules/vue"),
},
},
});
Or if you used vue-cli to create your project, edit the vue.config.js:
const { defineConfig } = require("#vue/cli-service");
const path = require("path");
module.exports = defineConfig({
// ...
chainWebpack(config) {
config.resolve.symlinks(false);
config.resolve.alias.set("vue", path.resolve("./node_modules/vue"));
},
});
Thanks to #mikelplhts
On vite + esbuild I used:
export default defineConfig({
...
resolve: {
alias: [
...
{
find: 'vue',
replacement: path.resolve("./node_modules/vue"),
},
],
},
...

Storybook/Vue: style not applied

I installed storybook via the vue-cli and added a .scss file in my preview.js:
import "assets/scss/core.scss";
import Vue from "vue";
import CompositionApi from "#vue/composition-api";
Vue.use(CompositionApi);
where "assets" is an alias configured in my vue.config.js to refer to the src/assets path. According to the docs :
The webpack config used for storybook is resolved from vue-cli-service, which means you don't need to have any special webpack section in storybook config folder.
So the path should ne correctly resolved, right ? However the style does not seem to be loaded as it is not applied to my components.
Am I missing something ?
FYI, here is my main.js:
module.exports = {
core: {
builder: "webpack5",
},
stories: ["../../src/**/*.stories.#(js|jsx|ts|tsx|mdx)"],
addons: [
"#storybook/addon-essentials",
"#storybook/addon-links",
],
};
And my vue.config.js :
const path = require("path");
module.exports = {
configureWebpack: {
resolve: {
alias: {
//aliases go here
"#": path.resolve(__dirname, "src"),
assets: path.resolve(__dirname, "./src/assets"),
},
},
},
css: {
loaderOptions: {
scss: {
additionalData: `#import 'assets/scss/variables';`,
},
},
},
};
Thanks !

Vue 3 Storybook Scss and Tailwind Configuration

I want to use Storybook in combination with Vue 3, SCSS and TailwindCSS.
I achieved to configure storybook that TailwindCSS is loading but it fails loading the appropriate component style.
In the .storybook Folder I added the following webpack.config.js:
const path = require('path');
module.exports = ({ config, mode }) => {
config.module.rules.push({
test: /\.scss$/,
use: [
require.resolve("vue-style-loader"),
require.resolve("css-loader"),
require.resolve("sass-loader")
],
});
config.module.rules.push({
test: /\.(css|scss)$/,
loaders: [
{
loader: 'postcss-loader',
options: {
sourceMap: true,
config: {
path: './.storybook/',
},
},
},
],
include: path.resolve(__dirname, '../storybook/'),
});
return config;
};
In the preview.js File in .storybook Folder I added the "Global" CSS to initialise Tailwind. (works fine tho)
import '../src/index.css'
export const parameters = {
actions: { argTypesRegex: "^on[A-Z].*" },
}
And I added a postcss.config.js in the .storybook Folder.
var tailwindcss = require('tailwindcss');
module.exports = {
plugins: [
require('postcss-import')(),
tailwindcss('../tailwind.config.js'),
require('autoprefixer'),
],
};
This setup is able to show / build stories but without the corresponding Vue Component Style.
An example component which I wanna preview in storybook is "Fact.vue".
<template>
<div class="fact"><slot /></div>
</template>
<script>
export default {};
</script>
<style lang="scss">
#use "./src/scss/atoms/fact.scss";
</style>
As you can see I #use the corresponding style
fact.scss:
.fact {
#apply font-bold text-4xl;
}
But how can I make sure that the style of the component is loaded correctly? According to Google Inspector, the #apply is not resolved correctly.

How can I configure my Webpack file in Storybook correctly to compile my CSS with PostCSS?

I have a Vue CLI up and running successfully with PostCSS and all of the plugins I require. However, when it comes to setting up the same PostCSS config for Storybook, no matter which combination of things I try from various sources that I've come across, I cannot get my Webpack file to compile correctly.
.storybook/postcss.config.js
module.exports = {
plugins: {
autoprefixer: {},
'postcss-nested': {},
'postcss-custom-media': {},
'postcss-advanced-variables': {},
},
};
.storybook/webpack.config.js
const path = require('path');
const rootPath = path.resolve(__dirname, '../src');
module.exports = ({ config, mode }) => {
config.module.rules.push({
test: /\.css$/,
use: [
'style-loader',
{ loader: 'css-loader', options: { importLoaders: 1 } },
'postcss-loader',
],
});
config.resolve.alias['#'] = rootPath;
return config;
};
./storybook.config.js
import { configure } from '#storybook/vue';
import Vue from 'vue';
import Vuex from 'vuex';
import '../src/css/main.css';
import '../src/stories/main.css';
Vue.use(Vuex);
function loadStories() {
require('../src/stories');
}
configure(loadStories, module);
Error
ERROR in ./src/css/main.css (./node_modules/#storybook/core/node_modules/css-loader/dist/cjs.js??ref--3-1!./node_modules/postcss-loader/src??postcss!./node_modules/style-loader!./node_modules/css-loader??ref--6-1!./node_modules/postcss-loader/src!./src/css/main.css)
Module build failed (from ./node_modules/postcss-loader/src/index.js):
SyntaxError
(2:1) Unknown word
1 |
> 2 | var content = require("!!../../node_modules/css-loader/index.js??ref--6-1!../../node_modules/postcss-loader/src/index.js!./main.css");
| ^