Skip to content

Plugin does not work from nextjs v14.1.2 and onwards #4

Open
@arnoBruynseels

Description

@arnoBruynseels

The plugin works perfectly on nextjs v14.1.1 but once you install nextjs v14.1.2 everything breaks.

Nextjs complains that I need to use the 'use client' directive for the external component library I added to the plugin config.

Any fixes?

Activity

coder-xiaotian

coder-xiaotian commented on Mar 26, 2024

@coder-xiaotian
Owner

The plugin works perfectly on nextjs v14.1.1 but once you install nextjs v14.1.2 everything breaks.

Nextjs complains that I need to use the 'use client' directive for the external component library I added to the plugin config.

Any fixes?

I did not reproduce this issue in my repo used nextjsv14.1.4. Please provide your code to better reproduce the issue.

arnoBruynseels

arnoBruynseels commented on Mar 28, 2024

@arnoBruynseels
Author

The plugin works perfectly on nextjs v14.1.1 but once you install nextjs v14.1.2 everything breaks.
Nextjs complains that I need to use the 'use client' directive for the external component library I added to the plugin config.
Any fixes?

I did not reproduce this issue in my repo used nextjsv14.1.4. Please provide your code to better reproduce the issue.

In your provided repo you don't have any swcPlugins defined.

This is how we use the plugin:

image

coder-xiaotian

coder-xiaotian commented on Mar 28, 2024

@coder-xiaotian
Owner

The plugin works perfectly on nextjs v14.1.1 but once you install nextjs v14.1.2 everything breaks.
Nextjs complains that I need to use the 'use client' directive for the external component library I added to the plugin config.
Any fixes?

I did not reproduce this issue in my repo used nextjsv14.1.4. Please provide your code to better reproduce the issue.

In your provided repo you don't have any swcPlugins defined.

This is how we use the plugin:

image

I can start success in my repo with antd. I think it's probably an issue with the directory structure of your component library. The export directory structure of antd is as follows:
image
I can't find @spot/ui-components in npm. Please provide more information about it. And you can provide the error logs.

tjones4701

tjones4701 commented on Apr 15, 2024

@tjones4701

Hey, this no longer works with next 14.2.0, any chance of a fix for this?
: failed to run Wasm plugin transform. Please ensure the version of swc_core used by the plugin is compatible with the host runtime.

coder-xiaotian

coder-xiaotian commented on Apr 16, 2024

@coder-xiaotian
Owner

Hey, this no longer works with next 14.2.0, any chance of a fix for this? : failed to run Wasm plugin transform. Please ensure the version of swc_core used by the plugin is compatible with the host runtime.

I get it. What is your OS version useing.

coder-xiaotian

coder-xiaotian commented on Apr 16, 2024

@coder-xiaotian
Owner

Hey, this no longer works with next 14.2.0, any chance of a fix for this?嘿,这不再适用于下一个 14.2.0,有修复这个问题的机会吗? : failed to run Wasm plugin transform. Please ensure the version of swc_core used by the plugin is compatible with the host runtime.:无法运行 Wasm 插件转换。请确保插件使用的 swc_core 版本与主机运行时兼容。

I fixed it. You can update use-client to 1.2.0.

arnoBruynseels

arnoBruynseels commented on Aug 23, 2024

@arnoBruynseels
Author

Hi it's me again.

I'm trying to up our Nextjs version from 14.1.1 to to lastest (14.2.6).

Steps I took:

  1. Install Nextjs version 14.2.6
  2. Install use-client version 1.2.0
  3. Applied following config:

image

NOTE: all the @spot packages are private internal repositories. We create our own component library. This component library is build using React and Vite where all components are exported in an index.js file

Below is what it looks like:

image

  1. Run the Nextjs application
  2. Following error occurs:

image

Where does it go wrong?
Did we implement or use this package wrong?
Did we implement or expose our UI library the wrong way?

Please help, we can't seem to find the source of the problem.

Thanks!

coder-xiaotian

coder-xiaotian commented on Aug 25, 2024

@coder-xiaotian
Owner

Hi it's me again.

I'm trying to up our Nextjs version from 14.1.1 to to lastest (14.2.6).

Steps I took:

  1. Install Nextjs version 14.2.6
  2. Install use-client version 1.2.0
  3. Applied following config:

image

NOTE: all the @spot packages are private internal repositories. We create our own component library. This component library is build using React and Vite where all components are exported in an index.js file

Below is what it looks like:

image

  1. Run the Nextjs application
  2. Following error occurs:

image

Where does it go wrong? Did we implement or use this package wrong? Did we implement or expose our UI library the wrong way?

Please help, we can't seem to find the source of the problem.

Thanks!

Please provide the [local]/users page code and this file code.
image

arnoBruynseels

arnoBruynseels commented on Aug 26, 2024

@arnoBruynseels
Author

``> > Hi it's me again.

I'm trying to up our Nextjs version from 14.1.1 to to lastest (14.2.6).
Steps I took:

  1. Install Nextjs version 14.2.6
  2. Install use-client version 1.2.0
  3. Applied following config:

image
NOTE: all the @spot packages are private internal repositories. We create our own component library. This component library is build using React and Vite where all components are exported in an index.js file
Below is what it looks like:
image

  1. Run the Nextjs application
  2. Following error occurs:

image
Where does it go wrong? Did we implement or use this package wrong? Did we implement or expose our UI library the wrong way?
Please help, we can't seem to find the source of the problem.
Thanks!

Please provide the [local]/users page code and this file code. image

[local]/users page code:

image

UserPageContent code:

image

'use client';

import { AgGrid, BooleanText, agGridCssClasses } from '@spot/ui-components';
import type { AgGridProps } from '@spot/ui-components';
import type { ICellRendererParams, RowClassParams } from 'ag-grid-community';
import { useTranslations } from 'next-intl';
import type { ReactNode } from 'react';
import { useCallback, useMemo } from 'react';
import { useState } from 'react';

import UserModalContent from '@/app/[locale]/users/_components/users-page-content/components/user-modal-content/UserModalContent';
import UserModalFooter from '@/app/[locale]/users/_components/users-page-content/components/user-modal-footer/UserModalFooter';
import type { UserModalContentTabKey } from '@/app/[locale]/users/_components/users-page-content/components/user-modal-header/UserModalHeader';
import UserModalHeader from '@/app/[locale]/users/_components/users-page-content/components/user-modal-header/UserModalHeader';
import type { User } from '@/generated/graphql/types';
import { useSelector } from '@/lib/redux/redux-store';
import { selectUsersData } from '@/lib/redux/slices/user-management/selectors';

const UsersPageContent = () => {
  const t = useTranslations();

  const users = useSelector(selectUsersData);

  const [modalActiveTabKey, setModalActiveTabKey] = useState<UserModalContentTabKey>('generalTab');

  const modalTitle = useCallback(
    (selectedRecord: unknown): ReactNode => {
      return (
        <UserModalHeader
          user={selectedRecord as User}
          selectedTabKey={modalActiveTabKey}
          setSelectedTabKey={setModalActiveTabKey}
        />
      );
    },
    [modalActiveTabKey],
  );

  const modalContent = useCallback(
    (selectedRecord: unknown): ReactNode => {
      return <UserModalContent user={selectedRecord as User} selectedTabKey={modalActiveTabKey} />;
    },
    [modalActiveTabKey],
  );

  const modalFooter = useCallback(
    (selectedRecord: unknown): ReactNode => {
      return <UserModalFooter isCopyVisible={modalActiveTabKey === 'debugTab'} user={selectedRecord as User} />;
    },
    [modalActiveTabKey],
  );

  const columnDefs: AgGridProps['columnDefs'] = useMemo(() => {
    return [
      {
        headerName: t('application-common.user'),
        children: [
          {
            field: 'user',
            headerName: t('application-common.userID'),
          },
          {
            field: 'firstName',
            headerName: t('application-common.firstName'),
          },
          {
            field: 'lastName',
            headerName: t('application-common.lastName'),
          },
          {
            field: 'email',
            headerName: t('application-common.email'),
          },
          {
            field: 'department',
            headerName: t('application-common.department'),
          },

          {
            field: 'organisation',
            headerName: t('application-common.organisation'),
          },
        ],
      },
      {
        headerName: t('application-common.privileges'),
        children: [
          {
            field: 'hasAccess',
            headerName: t('application-common.access'),
            cellRenderer: (params: ICellRendererParams) => {
              return (
                <BooleanText
                  value={params.value}
                  variant={params.value ? 'success' : 'danger'}
                  trueText="Normal"
                  falseText="Blocked"
                />
              );
            },
            filterValueGetter: (params) => {
              return params.data.hasAccess ? t('application-common.normal') : t('application-common.blocked');
            },
          },
          {
            field: 'isAdmin',
            headerName: t('application-common.admin'),
            cellRenderer: (params: ICellRendererParams) => {
              return <BooleanText value={params.value} variant={params.value ? 'success' : 'danger'} />;
            },
            filterValueGetter: (params) => {
              return params.data.isAdmin ? t('application-common.yes') : t('application-common.no');
            },
            minWidth: 115,
            columnGroupShow: 'open',
          },
          {
            field: 'isWyreUser',
            headerName: t('application-common.wyreUser'),
            cellRenderer: (params: ICellRendererParams) => {
              return <BooleanText value={params.value} variant={params.value ? 'success' : 'danger'} />;
            },
            filterValueGetter: (params) => {
              return params.data.isWyreUser ? t('application-common.yes') : t('application-common.no');
            },
            minWidth: 115,
            columnGroupShow: 'open',
          },
          {
            field: 'isBusinessExpert',
            headerName: t('application-common.businessExpert'),
            cellRenderer: (params: ICellRendererParams) => {
              return <BooleanText value={params.value} variant={params.value ? 'success' : 'danger'} />;
            },
            filterValueGetter: (params) => {
              return params.data.isBusinessExpert ? t('application-common.yes') : t('application-common.no');
            },
            minWidth: 115,
            columnGroupShow: 'open',
          },
        ],
      },
      {
        headerName: t('application-common.usage'),
        children: [
          {
            field: 'lastSeen',
            headerName: t('application-common.lastName'),
          },
          {
            field: 'firstSeen',
            headerName: t('application-common.firstSeen'),
            minWidth: 115,
            columnGroupShow: 'open',
          },
        ],
      },
    ];
  }, [t]);

  const getRowClass: AgGridProps['getRowClass'] = useCallback((params: RowClassParams) => {
    return params.data.hasAccess === false ? agGridCssClasses.DangerBackground : '';
  }, []);

  const defaultColDef: AgGridProps['defaultColDef'] = useMemo(() => {
    return {
      sortable: true,
      resizable: true,
      filter: true,
    };
  }, []);

  const onCloseLogic: AgGridProps['onCloseLogic'] = useCallback(() => {
    setModalActiveTabKey('generalTab');
  }, []);

  const dataViewModalConfig: AgGridProps['dataViewModalConfig'] = useMemo(() => {
    return {
      hasSlideTabs: true,
      title: modalTitle,
      customContent: modalContent,
      customFooter: modalFooter,
    };
  }, [modalContent, modalFooter, modalTitle]);

  const columnsState: AgGridProps['columnsState'] = useMemo(() => {
    return [
      {
        colId: 'lastSeen',
        sort: 'desc',
      },
    ];
  }, []);

  return (
    <AgGrid
      showRecordCount
      enableGlobalFilter
      enableDataViewModal
      rowData={users}
      columnDefs={columnDefs}
      getRowClass={getRowClass}
      defaultColDef={defaultColDef}
      onCloseLogic={onCloseLogic}
      dataViewModalConfig={dataViewModalConfig}
      columnsState={columnsState}
    />
  );
};

export default UsersPageContent;

TimestampRefreshButton code:

Transpiled & Compiled:

image

Actual Component code:

import type { ButtonProps } from '@lib/inputs/button/Button';
import Button from '@lib/inputs/button/Button';
import Icon from '@lib/utilities/icon/Icon';
import IntervalIndication from '@lib/utilities/timestamp-refresh-button/components/interval-indication/IntervalIndication';
import TimeIndication from '@lib/utilities/timestamp-refresh-button/components/time-indication/TimeIndication';
import clsx from 'clsx';
import { addWeeks, isAfter, isSameDay, isSameWeek, isTomorrow, isYesterday } from 'date-fns';
import type { Moment } from 'moment';
import type { CSSProperties, PropsWithChildren } from 'react';

import styles from './TimestampRefreshButton.module.css';

export interface TimestampRefreshButtonProps {
  /**
   * Optional styling
   */
  style?: CSSProperties;
  /**
   * Optional className
   */
  className?: string;
  /**
   * Optional buttonText
   */
  buttonText?: string;
  /**
   * Optional plainDateFormat
   */
  plainDateFormat?: boolean;
  /**
   * Optional intervalSeparator
   */
  intervalSeparator?: string;
  /**
   * Optional onClick
   */
  handleClick: ButtonProps['handleClick'];
  /**
   * Optional time
   */
  time?: Date | Moment | null;
  /**
   * Optional timeFormat
   */
  timeFormat?: string;
  /**
   * Optional timeTo
   */
  timeTo?: Date | Moment;
  /**
   * Optional timeToFormat
   */
  timeToFormat?: string;
}

/**
 * TimestampRefreshButton component
 */
const TimestampRefreshButton = ({
  style,
  className,
  buttonText = 'Refresh',
  plainDateFormat = false,
  intervalSeparator = ' ... ',
  handleClick,
  time = new Date(),
  timeFormat = 'yyyy-MM-dd HH:mm',
  timeTo,
  timeToFormat = 'yyyy-MM-dd HH:mm',
}: PropsWithChildren<TimestampRefreshButtonProps>) => {
  let validTime: Date | null = null;

  if (time) {
    validTime = time instanceof Date ? time : time.toDate();
  }

  const today = new Date();

  let validTimeTo = timeTo;

  let relativeTimeFormat = 'yyyy-MM-dd HH:mm';

  if (timeTo) {
    validTimeTo = timeTo instanceof Date ? timeTo : timeTo.toDate();
  }

  if (!plainDateFormat && validTime !== null) {
    if (isSameDay(today, validTime)) {
      relativeTimeFormat = "'Today' HH:mm";
    } else if (isTomorrow(validTime)) {
      relativeTimeFormat = "'Tomorrow' HH:mm";
    } else if (isSameWeek(addWeeks(today, 1), validTime)) {
      relativeTimeFormat = 'yyyy-MM-dd HH:mm';
    } else if (isSameWeek(addWeeks(today, -1), validTime)) {
      relativeTimeFormat = 'yyyy-MM-dd HH:mm';
    } else if (isYesterday(validTime)) {
      relativeTimeFormat = "'Yesterday' HH:mm";
    } else if (isAfter(validTime, addWeeks(today, 1))) {
      relativeTimeFormat = 'yyyy-MM-dd HH:mm';
    }
  }

  const renderTime = () => {
    if (validTime === null) {
      return null;
    }

    if (timeTo) {
      return (
        <IntervalIndication
          time={validTime}
          timeFormat={timeFormat}
          timeTo={validTimeTo as Date}
          timeToFormat={timeToFormat}
          intervalSeparator={intervalSeparator}
          plainDateFormat={plainDateFormat}
          relativeTimeFormat={relativeTimeFormat}
        />
      );
    }

    return (
      <TimeIndication
        time={validTime}
        timeFormat={timeFormat}
        plainDateFormat={plainDateFormat}
        relativeTimeFormat={relativeTimeFormat}
      />
    );
  };

  return (
    <div className={clsx(className, [styles.timestampRefreshButton])} style={style}>
      {renderTime()}
      <Button handleClick={handleClick} variant="success" size="extra-small" className={styles.refreshButton}>
        <Icon icon="cached" size={15} className={styles.refreshIcon} />
        {buttonText}
      </Button>
    </div>
  );
};

export default TimestampRefreshButton;

coder-xiaotian

coder-xiaotian commented on Aug 27, 2024

@coder-xiaotian
Owner

@arnoBruynseels You can try these two ways.

  1. add "@lib/" to config like this include: ["@lib/", ...];
  2. you can change change the import way from @spot/ui-components, for example change import { AgGrid } from '@spot/ui-components' to import AgGrid from '@spot/ui-components/your-component-path'.
arnoBruynseels

arnoBruynseels commented on Aug 28, 2024

@arnoBruynseels
Author

@arnoBruynseels You can try these two ways.

  1. add "@lib/" to config like this include: ["@lib/", ...];
  2. you can change change the import way from @spot/ui-components, for example change import { AgGrid } from '@spot/ui-components' to import AgGrid from '@spot/ui-components/your-component-path'.

Thanks, I will try this and keep you posted!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @arnoBruynseels@coder-xiaotian@tjones4701

        Issue actions

          Plugin does not work from nextjs v14.1.2 and onwards · Issue #4 · coder-xiaotian/swc-useclient