Skip to content
This repository was archived by the owner on Jun 28, 2025. It is now read-only.
This repository was archived by the owner on Jun 28, 2025. It is now read-only.

[Issue] storybook build throws Parse error @:1:1 while storybook dev works #570

Description

@oxypomme

What version of vite are you using?

4.2.1

System info and storybook versions

System:
OS: Linux 5.14 Ubuntu 20.04.2 LTS (Focal Fossa)
CPU: (20) x64 12th Gen Intel(R) Core(TM) i7-12700H
Binaries:
Node: 18.15.0 - ~/.nvm/versions/node/v18.15.0/bin/node
Yarn: 1.22.19 - ~/.nvm/versions/node/v18.15.0/bin/yarn
npm: 8.19.4 - ~/Documents/Work/ezreeport/node_modules/.bin/npm
Browsers:
Firefox: 111.0.1
npmPackages:
@storybook/addon-essentials: ^7.0.0 => 7.0.2
@storybook/addon-interactions: ^7.0.0 => 7.0.2
@storybook/addon-links: ^7.0.0 => 7.0.2
@storybook/addons: ^7.0.0 => 7.0.2
@storybook/blocks: ^7.0.0 => 7.0.2
@storybook/testing-library: ^0.0.13 => 0.0.13
@storybook/vue: ^7.0.0 => 7.0.2
@storybook/vue-vite: ^7.0.0 => 7.0.2

Describe the Bug

I've got an issue where running storybook dev works and I can access storybook through a web browser with no problems ...

Details
> storybook dev -p 6006

@storybook/cli v7.0.2

info => Starting manager..
building in dev mode
╭─────────────────────────────────────────────────────╮
│                                                     │
│   Storybook 7.0.2 for vue-vite started              │
│   261 ms for manager and 406 ms for preview         │
│                                                     │
│    Local:            http://localhost:6006/         │
│    On your network:  http://172.16.101.136:6006/    │
│                                                     │
╰─────────────────────────────────────────────────────╯
Neither '~/mixins/ezr.vue' nor '~/mixins/ezr.js(x)' or '~/mixins/ezr/index.js(x)' or '~/mixins/ezr/index.ts(x)' could be found in '/home/sublet/Documents/Work/ezreeport/src/vue/src/components/public/tasks'
09:40:10 [vite] ✨ new dependencies optimized: vuetify/lib, vuedraggable
09:40:10 [vite] ✨ optimized dependencies changed. reloading

... while running storybook build throws an error Parse error @:1:1 by vite:build-import-analysis.

Details
> storybook build

@storybook/cli v7.0.2

info => Cleaning outputDir: /storybook-static
info => Loading presets
info => Building manager..
info => Manager built (221 ms)
info => Copying static files: <rootDir>/node_modules/@storybook/manager/static at <rootDir>/storybook-static/sb-common-assets
vite v4.2.1 building for production...

./sb-common-assets/fonts.css doesn't exist at build time, it will remain unchanged to be resolved at runtime
transforming (79) .storybook/plugins/vuetify.tsNeither '~/mixins/ezr.vue' nor '~/mixins/ezr.js(x)' or '~/mixins/ezr/index.js(x)' or '~/mixins/ezr/index.ts(x)' could be found in '<rootDir>/src/components/internal/history'
✓ 299 modules transformed.
✓ built in 2.84s
[vite:build-import-analysis] Parse error @:1:1
file: <rootDir>/src/components/public/EzrProvider.vue
ERR! Error: Parse error @:1:1
ERR!     at parse$e (file://<rootDir>/node_modules/vite/dist/node/chunks/dep-79892de8.js:16018:355)
ERR!     at Object.transform (file://<rootDir>/node_modules/vite/dist/node/chunks/dep-79892de8.js:45421:27)
ERR!  Error: Parse error @:1:1
ERR!     at parse$e (file://<rootDir>/node_modules/vite/dist/node/chunks/dep-79892de8.js:16018:355)
ERR!     at Object.transform (file://<rootDir>/node_modules/vite/dist/node/chunks/dep-79892de8.js:45421:27) {
ERR!   idx: 0,
ERR!   id: '<rootDir>/src/components/public/EzrProvider.vue',
ERR!   hook: 'transform',
ERR!   code: 'PLUGIN_ERROR',
ERR!   plugin: 'vite:build-import-analysis',
ERR!   watchFiles: [
ERR!     ... 728 more items
ERR!   ]
ERR! }

(I skipped watchFiles and hidden paths because it doesn't seems revelent and yes, I tried to fix the issue with ~/mixins/ezr.vue and it didn't solve my problem)

From what I understand, the issue may be from EzrProvider.vue while it that seems perfectly right :

Details
// src/EzrProvider.vue
<template>
  <div v-if="ready">
    <slot />
  </div>
</template>

<script lang="ts">
import { defineComponent, type PropType } from 'vue';
import * as sdk from 'ezreeport-sdk-js';
import { type InjectedEzReeport, InjectionEzReeportKey } from '~/mixins/ezr';

export default defineComponent({
  props: {
    token: {
      type: String as PropType<string | undefined>,
      default: undefined,
    },
    apiUrl: {
      type: String,
      default: import.meta.env.VITE_REPORT_API,
    },
    namespaceLogoUrl: {
      type: String,
      default: import.meta.env.VITE_NAMESPACES_LOGO_URL,
    },
    namespaceLabel: {
      type: Object as PropType<Record<string, string>>,
      default: () => {},
    },
  },
  data: (): InjectedEzReeport['data'] => ({
    ready: false,
    auth: {
      permissions: undefined,
      user: undefined,
    },
    namespaces: {
      data: [],
      logoUrl: '',
    },
  }),
  watch: {
    apiUrl(value: string) {
      sdk.setup.setURL(value);
    },
    namespaceLogoUrl(value: string) {
      this.namespaces.logoUrl = value;
    },
    // eslint-disable-next-line func-names
    '$i18n.locale': function () {
      this.registerNamespaceLocalization();
    },
    token(value?: string) {
      if (value) {
        this.login(value);
        return;
      }
      this.logout();
    },
  },
  provide() {
    const $ezReeport = {
      sdk,

      tcNamespace: (capitalize?: boolean, choice?: number) => {
        const res = this.$tc('namespace', choice).toString();

        if (capitalize) {
          return `${res.at(0)?.toLocaleUpperCase() ?? ''}${res.slice(1)}`;
        }
        return res;
      },

      fetchNamespaces: (force?: boolean) => this.fetchNamespaces(force),
      login: (token: string) => this.login(token),
      logout: () => this.logout(),
      hasGeneralPermission: (permission: string) => this.hasGeneralPermission(permission),
      hasNamespacedPermission: (
        permission: string,
        namespaces: string[],
      ) => this.hasNamespacedPermission(permission, namespaces),
    };

    Object.defineProperties(
      $ezReeport,
      {
        data: {
          enumerable: true,
          get: () => this.$data,
        },
        isLogged: {
          enumerable: true,
          get: () => this.auth.user !== undefined,
        },
      },
    );

    return {
      [InjectionEzReeportKey]: $ezReeport,
    };
  },
  mounted() {
    sdk.setup.setURL(this.apiUrl);
    this.namespaces.logoUrl = this.namespaceLogoUrl;
    this.registerNamespaceLocalization();
    if (this.token) {
      this.login(this.token);
    }

    // Rendering childrens will trigger requests to API
    // and it can be before we set the correct URL.
    // ? maybe a v-if on each public component is better than here
    this.ready = true;
  },
  methods: {
    registerNamespaceLocalization() {
      // eslint-disable-next-line no-restricted-syntax
      for (const [locale, label] of Object.entries(this.namespaceLabel)) {
        this.$i18n.mergeLocaleMessage(locale, { namespace: label });
      }
    },
    /**
     * Add token into SDK, fetch permissions & current user
     *
     * @param token The API token for ezMESURE
     */
    login(token: string) {
      sdk.auth.login(token);

      Promise.allSettled([
        sdk.auth.getCurrentPermissions()
          .then(({ content }) => { this.auth.permissions = content; }),

        sdk.auth.getCurrentUser()
          .then(({ content }) => { this.auth.user = content; }),
      ]).then((results) => {
        // eslint-disable-next-line no-restricted-syntax
        for (const res of results) {
          if (res.status === 'rejected') {
            console.error('[ezReeport-vue]', res.reason.message);
          }
        }
      });
    },
    /**
     * Remove token from SDK, clear permissions & current user
     */
    logout() {
      sdk.auth.logout();
      this.auth.permissions = undefined;
      this.auth.user = undefined;
    },
    /**
     * Shorthand to fetch namespaces and make it available into whole Vue.
     *
     * If namespaces was already fetched before, it will not re-fetch
     *
     * @param force Force reload
     */
    async fetchNamespaces(force = false): Promise<sdk.namespaces.Namespace[]> {
      if (force || this.namespaces.data.length <= 0) {
        if (this.hasNamespacedPermission('auth-get-namespaces', [])) {
          const { content } = await sdk.auth.getCurrentNamespaces();
          if (!content) {
            throw new Error(this.$t('errors.no_data').toString());
          }

          this.namespaces.data = content;
        } else {
          this.namespaces.data = [];
        }
      }
      return this.namespaces.data;
    },
    /**
     * Check if logged user have permission to do some action
     *
     * @param permission The permission name
     *
     * @returns If the user have the permission
     */
    hasGeneralPermission(permission: string) {
      return !!this.auth.permissions?.general[permission];
    },
    /**
     * Check if logged user have permission in namespaces to do some action
     *
     * @param permission The permission name
     * @param namespaces The concerned namespaces. If empty will attempt
     * to find at least one in all possibles
     *
     * @returns If the user have the permission
     */
    hasNamespacedPermission(permission: string, namespaces: string[]) {
      let entries = Object.entries(this.auth.permissions?.namespaces ?? {});

      if (namespaces.length > 0) {
        entries = entries.filter(([namespace]) => namespaces.includes(namespace));
      }
      return !!entries.find(([, perms]) => perms[permission]);
    },
  },
});
</script>

<style scoped>

</style>

<i18n lang="yaml">
en:
  namespace: 'namespace'
  errors:
    no_data: 'An error occurred when fetching data'
fr:
  namespace: 'espace'
  errors:
    no_data: 'Une erreur est survenue lors de la récupération des données'
</i18n>

I also suspect that the issue may come from .storybook/preview.ts or .storybook/main.ts :

Details
// .storybook/main.ts
/* eslint-disable import/no-import-module-exports */
import { mergeConfig } from 'vite';
import type { StorybookConfig } from '@storybook/types';
import type { StorybookConfigVite } from '@storybook/builder-vite';

const config: StorybookConfig & StorybookConfigVite = {
  stories: [
    // '../src/**/*.mdx',
    '../src/**/*.stories.@(js|jsx|ts|tsx)',
  ],
  addons: [
    '@storybook/addon-links',
    '@storybook/addon-essentials',
    '@storybook/addon-interactions',
  ],
  framework: {
    name: '@storybook/vue-vite',
    options: {},
  },
  docs: {
    autodocs: 'tag',
  },
  core: {
    builder: '@storybook/builder-vite',
  },
  typescript: {
    check: false,
  },
  viteFinal: (cfg) => mergeConfig(cfg, {
    optimizeDeps: {
      include: [
        'vuetify',
        'vue-i18n',
        'vuetify/src/locale',
        '@storybook/addon-essentials/docs/mdx-react-shim',
        '@storybook/blocks',
      ],
    },
  }),
};

module.exports = config;
Details
// .storybook/preview.ts
/// <reference types="../src/types/env" />

import Vue, { defineComponent } from 'vue';
import Vuetify from 'vuetify';
import type { Decorator, Parameters } from '@storybook/vue';
import i18n from './plugins/i18n';
import vuetify from './plugins/vuetify';
import ezReeport from '../src';

// Setup Vuetify
Vue.use(Vuetify);

// Setup i18n
// eslint-disable-next-line no-underscore-dangle
Vue.prototype._i18n = i18n;

// Setup ezReeport plugin
Vue.use(ezReeport);
if (!import.meta.env.VITE_AUTH_TOKEN) {
  console.warn('[ezReeport-storybook] Auth token not found');
}

export const parameters: Parameters = {};

export const globalTypes = {
  theme: {
    name: 'Theme',
    description: 'Global theme for components',
    defaultValue: 'light',
    toolbar: {
      icon: 'paintbrush',
      items: ['light', 'dark'],
      dynamicTitle: true,
    },
  },
  locale: {
    name: 'Locale',
    description: 'Internationalization locale',
    defaultValue: 'en',
    toolbar: {
      icon: 'globe',
      items: [
        { value: 'en', title: 'English' },
        { value: 'fr', title: 'Français' },
      ],
    },
  },
};

export const decorators: Decorator[] = [
  (story, context) => defineComponent({
    name: 'StorybookPreview',
    vuetify,
    i18n,
    components: { story },
    props: {
      theme: {
        type: String,
        default: context.globals.theme,
      },
      locale: {
        type: String,
        default: context.globals.locale,
      },
    },
    data: () => ({
      token: import.meta.env.VITE_AUTH_TOKEN,
    }),
    watch: {
      theme: {
        immediate: true,
        handler(val) {
          this.$vuetify.theme.dark = val === 'dark';
        },
      },
      locale: {
        immediate: true,
        handler(val) {
          this.$i18n.locale = val;
        },
      },
    },
    computed: {
      namespaceLabel() {
        return {
          en: 'namespace | namespaces',
          fr: 'établissement | établissements',
        };
      },
    },
    template: `
        <v-app>
          <ezr-provider :token="token" :namespaceLabel="namespaceLabel">
            <v-container fluid>
              <story />
            </v-container>
          </ezr-provider>
        </v-app>
      `,
  }),
];

I think this issue is very specific to my setup, so I can't really reproduce in a codesandbox or something (tho I really like to) so I linked to the repo at a commit where the issue happens.

Link to Minimal Reproducible Example

https://github.com/ezpaarse-project/ezreeport/tree/19622bb039ef22177222b50f01eb57f683f39c1e/src/vue

Participation

  • I am willing to submit a pull request for this issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions