lightweight-charts icon indicating copy to clipboard operation
lightweight-charts copied to clipboard

DOCS: How to use in SSR context

Open jerssonMA opened this issue 3 years ago • 23 comments

Lightweight Charts Version: 3.1.3

Steps/code to reproduce: Encapsulating lightweight-charts in an external library.

Actual behavior: I have my own library which encapsulates lightweight-charts and when installing it generates this error, I am using rollup to compress the files with a cjs format I cannot understand the conflict.

Expected behavior: Module should be found.

I don't know what I am missing

Screenshots:

Error

image

Rollup config

image

jerssonMA avatar Aug 07 '20 00:08 jerssonMA

It seems that rollup doesn't understand that it's module 🤔. Can you please create repro for that?

timocov avatar Aug 07 '20 11:08 timocov

It seems that rollup doesn't understand that it's module 🤔. Can you please create repro for that?

It is a private library... I could not share this access 😔. Do you require something specific about the implementation?

jerssonMA avatar Aug 07 '20 18:08 jerssonMA

It seems that rollup doesn't understand that it's module 🤔. Can you please create repro for that?

It is a private library... I could not share this access 😔. Do you require something specific about the implementation?

This error appears when including lightweight-charts in the rollup external config but if it is not included it generates this error: image

jerssonMA avatar Aug 08 '20 20:08 jerssonMA

The error is there for webpack as well. I've tried adding "type": "module" to package.json but that causes other errors.

blazeyo avatar Aug 11 '20 11:08 blazeyo

Steps to reproduce:

  • yarn create next-app
  • cd my-app
  • yarn add lightweight-charts
  • yarn dev # it works
  • add import { createChart } from 'lightweight-charts'; to pages/index.js
  • restart yarn dev and visit localhost:3000
  • the app throws a syntax error
SyntaxError: Unexpected token {
    at Module._compile (internal/modules/cjs/loader.js:720:23)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:787:10)
    at Module.load (internal/modules/cjs/loader.js:643:32)
    at Function.Module._load (internal/modules/cjs/loader.js:556:12)
    at Module.require (internal/modules/cjs/loader.js:683:19)
    at require (internal/modules/cjs/helpers.js:16:16)
    at Object.<anonymous> (/tmp/my-app/node_modules/lightweight-charts/index.js:6:19)
    at Module._compile (internal/modules/cjs/loader.js:776:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:787:10)
    at Module.load (internal/modules/cjs/loader.js:643:32)
[...]/lightweight-charts/dist/lightweight-charts.esm.development.js:7
import { bindToDevicePixelRatio } from 'fancy-canvas/coordinate-space';

blazeyo avatar Aug 11 '20 11:08 blazeyo

Steps to reproduce:

  • yarn create next-app
  • cd my-app
  • yarn add lightweight-charts
  • yarn dev # it works
  • add import { createChart } from 'lightweight-charts'; to pages/index.js
  • restart yarn dev and visit localhost:3000
  • the app throws a syntax error
SyntaxError: Unexpected token {
    at Module._compile (internal/modules/cjs/loader.js:720:23)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:787:10)
    at Module.load (internal/modules/cjs/loader.js:643:32)
    at Function.Module._load (internal/modules/cjs/loader.js:556:12)
    at Module.require (internal/modules/cjs/loader.js:683:19)
    at require (internal/modules/cjs/helpers.js:16:16)
    at Object.<anonymous> (/tmp/my-app/node_modules/lightweight-charts/index.js:6:19)
    at Module._compile (internal/modules/cjs/loader.js:776:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:787:10)
    at Module.load (internal/modules/cjs/loader.js:643:32)
[...]/lightweight-charts/dist/lightweight-charts.esm.development.js:7
import { bindToDevicePixelRatio } from 'fancy-canvas/coordinate-space';

My problem also occurs in a next-js application, I suspect it is due to a babel configuration but I cannot identify which one, this error also occurs when executing the unit tests with jest.

@timocov Do you know what the configuration could be? I understand that you use typescript, I suppose that when transpiling the code we have a configuration that we need to have in our babel.

jerssonMA avatar Aug 11 '20 15:08 jerssonMA

Ah, it seems that I understand what's going on here. That's because you're trying to import that module in nodejs environment, which requires either commonjs or esmodules (mjs and full path with extension). You can try to import standalone version in nodejs (it doesn't have any import and is just iife).

Related issues https://github.com/tradingview/lightweight-charts/issues/446 and https://github.com/tradingview/lightweight-charts/pull/484.

Maybe @NekitCorp or @azhang can help here?

timocov avatar Aug 14 '20 11:08 timocov

Yea, agreed with @timocov. Looks like it's not parsing the import statement correctly because it's not the full path including .js extension. Otherwise i'm not sure - not familiar with Next.js and webpack does seem to support es6 modules natively

azhang avatar Aug 14 '20 22:08 azhang

Ok, this can be worked around with a dynamic import in next. As mentioned by @NekitCorp here libraries don't usually throw fatal errors when they're imported in the SSR context, so that might be worth fixing.

Thanks for the library and all your hard work. It's absolutely fantastic!

blazeyo avatar Aug 15 '20 20:08 blazeyo

I think we need to add article in the docs for that (how to integrate in SSR context).

timocov avatar Aug 21 '20 07:08 timocov

Any idea on how this could be remedied in a Nuxt context? (#557 )

miketeix avatar Sep 01 '20 19:09 miketeix

@miketeix lightweight-charts cannot be instantiated in SSR context (because it creates canvases and all work is done with them). Do Nuxt have somrthing like dynamic loading? If so, I think you can use it to load library via it.

timocov avatar Sep 03 '20 11:09 timocov

Hey thanks the tip @timocov, it worked for me by loading third-party script using vue-meta for nuxt (https://vueschool.io/articles/vuejs-tutorials/how-to-load-third-party-scripts-in-nuxt-js/) Cheers!

miketeix avatar Sep 03 '20 13:09 miketeix

@timocov As it seems to me, need to make another version of the library for CommonJS modules and then there will be no problems on the server side. Then there will be no need to describe DOCS.

Now at package.json#main set in "main": "index.js" what is the entry point for node:

if (process.env.NODE_ENV === 'production') {
	module.exports = require('./dist/lightweight-charts.esm.production.js');
} else {
	module.exports = require('./dist/lightweight-charts.esm.development.js');
}

but in lightweight-charts.esm.development.js the first line goes ES modules import:

import { bindToDevicePixelRatio } from 'fancy-canvas/coordinate-space';

which leads to the errors described above.

Example package.json files of another library, which is also used only on the client side:

"main": "lib/cjs/index.js",
"module": "lib/es/index.js",

NekitCorp avatar Sep 17 '20 07:09 NekitCorp

make another version of the library for CommonJS modules and then there will be no problems on the server side

@NekitCorp what's purpose of importing the library directly on nodejs side? I hadn't a deal with SSR so I'm not quite know how exactly SSR on nodejs works. lightweight-charts just can't work on nodejs side, because it uses canvas elements mostly and don't know how to work in SSR, so I'd say the library should be imported in async way on nodejs side.

I agree that there is some issue with the library's package.json and index.js file - we shouldn't use commonjs for esm and vice-versa, thus we have to do one of:

  • generate commonjs bundle as well as esm one
  • remove main field from package.json, remove index.js file (which is cjs module basically) and add "type": "module" to the package.json (I prefer this one)

The question is - who expects and needs commonjs version of the library? Afaik all bundlers support and welcome esm version over cjs one. It looks like the library shouldn't be imported directly in nodejs context at all, isn't it?

Just wondering what's the best solution here might be...

timocov avatar Nov 12 '20 14:11 timocov

The question is - who expects and needs commonjs version of the library? Afaik all bundlers support and welcome esm version over cjs one. It looks like the library shouldn't be imported directly in nodejs context at all, isn't it?

I'm running into this running tests w/ jest which does run on node right? I ended up just ignoring it for now (as in https://stackoverflow.com/a/66340153/4200039) but at some point I would like to load this and run tests against it

jcrben avatar Apr 24 '21 16:04 jcrben

The question is - who expects and needs commonjs version of the library? Afaik all bundlers support and welcome esm version over cjs one. It looks like the library shouldn't be imported directly in nodejs context at all, isn't it?

Just wondering what's the best solution here might be...

Svelete REPL for one. I'm running into this problem with bundler.js/unpkg.com and getting 'Error: Cannot find "/coordinate-space" in [email protected]' when using the following imports :

    import {CrosshairMode} from 'lightweight-charts';
    import Chart from 'svelte-lightweight-charts/components/chart.svelte';
    import CandlestickSeries from 'svelte-lightweight-charts/components/candlestick-series.svelte'; 

Not sure how Fiddle links on the demo page work, does they do successfully complete the import....

dkwolfe4 avatar Oct 01 '21 19:10 dkwolfe4

import dynamic from 'next/dynamic';

const Chart = dynamic(() => import('@/components/Chart'));

I imported the component that create my chart this way, so it worked.

raulvictorrosa avatar Nov 20 '21 18:11 raulvictorrosa

@raulvictorrosa Hey, can you please share how this can be fixed for Next.js? I've tried with dunamic import, doesn't work. Here is the example with dynamic + lightweight-charts+next.js which simply doesn't work! :(

https://codesandbox.io/s/withered-meadow-2cvtn?file=/pages/index.jsx

darwin403 avatar Dec 14 '21 08:12 darwin403

@raulvictorrosa Hey, can you please share how this can be fixed for Next.js? I've tried with dunamic import, doesn't work. Here is the example with dynamic + lightweight-charts+next.js which simply doesn't work! :(

https://codesandbox.io/s/withered-meadow-2cvtn?file=/pages/index.jsx

Actually I did the same way as in your link but for me just worked in the development env, but when I try to build the app the error happens again in the build process.

raulvictorrosa avatar Dec 21 '21 04:12 raulvictorrosa

@raulvictorrosa Hey, can you please share how this can be fixed for Next.js? I've tried with dunamic import, doesn't work. Here is the example with dynamic + lightweight-charts+next.js which simply doesn't work! :(

https://codesandbox.io/s/withered-meadow-2cvtn?file=/pages/index.jsx

Found here the solution bro, actually I put this way, disabling the SSR, so this way worked in the build process and in dev env. This link can help also https://nextjs.org/docs/advanced-features/dynamic-import.

import dynamic from 'next/dynamic';

const Chart = dynamic(() => import('@/components/Chart'), { loading: () => <p>Loading ...</p>, ssr: false });

raulvictorrosa avatar Dec 21 '21 22:12 raulvictorrosa

@raulvictorrosa Hey, can you please share how this can be fixed for Next.js? I've tried with dunamic import, doesn't work. Here is the example with dynamic + lightweight-charts+next.js which simply doesn't work! :(

https://codesandbox.io/s/withered-meadow-2cvtn?file=/pages/index.jsx

This works btw

anikashc avatar Jan 21 '22 16:01 anikashc

For the people who use nextjs, if you don't want to use ssr: false -which is exclude lightweight-charts from getStaticProps build-, you may want to use next-transpile-modules instead.

  • Open your next.config.js file.
  • Export your config with using withTM hoc. Example:
/**
 * @type {import('next').NextConfig}
 */
const nextConfig = {...};

const withTM = require('next-transpile-modules')(['lightweight-charts', 'fancy-canvas']);

module.exports = withTM(nextConfig);

If you are using next 13.1 and later, please check https://github.com/tradingview/lightweight-charts/issues/543#issuecomment-1397511441 out.

mustaphaturhan avatar Jun 28 '22 11:06 mustaphaturhan

for astro you just need to do client:only="react" https://docs.astro.build/en/reference/directives-reference/#clientonly

pezdel avatar Sep 23 '22 21:09 pezdel

SOLVED: using the implementation from @mustaphaturhan helped. i tried everything but that. thank you

Hi, I still get the same error as above in NextJS and react. I am trying to create a component and I build the component as I do from above even using dynamic load, but the problem comes from the lightweight library itself

To reiterate, without even importing this component anywhere, I get thrown this error, so the dynamic code isn't solving anything while this component just renders by itself.

import { bindToDevicePixelRatio } from 'fancy-canvas/coordinate-space';
SyntaxError: Cannot use import statement outside a module

Here's my code: The error occurs at the import { createChart } from 'lightweight-charts'; line

MainChart Component

import React, { useEffect } from 'react';
import { createChart } from 'lightweight-charts';

export default function MainChart() {
  const ref = React.useRef();

  useEffect(() => {
    const chart = createChart(ref.current, { width: 400, height: 300 });
    const lineSeries = chart.addLineSeries();
    lineSeries.setData([
      { time: '2019-04-11', value: 80.01 },
      { time: '2019-04-12', value: 96.63 },
      { time: '2019-04-13', value: 76.64 },
      { time: '2019-04-14', value: 81.89 },
      { time: '2019-04-15', value: 74.43 },
      { time: '2019-04-16', value: 80.01 },
      { time: '2019-04-17', value: 96.63 },
      { time: '2019-04-18', value: 76.64 },
      { time: '2019-04-19', value: 81.89 },
      { time: '2019-04-20', value: 74.43 },
    ]);
  }, []);

  return (
    <>
      <div ref={ref} />
    </>
  );
}

0xAskar avatar Nov 17 '22 17:11 0xAskar

using the latest next.js version 13.1 you can now solve this with editing the next.config.js in the following way:

module.exports = {
  transpilePackages: ['lightweight-charts']
}

more info here in the release notes of 13.1

tamebadger avatar Jan 19 '23 19:01 tamebadger