Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

External javascript Libraries #98

Closed
ansarizafar opened this issue Aug 24, 2017 · 18 comments
Closed

External javascript Libraries #98

ansarizafar opened this issue Aug 24, 2017 · 18 comments

Comments

@ansarizafar
Copy link

Is it possible to import external javascript libraries?

@andreasbhansen
Copy link

andreasbhansen commented Aug 24, 2017

Yes. Example below implements the moment.js library.

days-ago.tsx

import { Component, Prop } from '@stencil/core';
import moment from 'moment';

@Component({
  tag: 'days-ago'
})
export class DaysAgo {

  @Prop() days: number;

  render() {
    return (
      <p>
        {this.days} days ago, the date was: { moment(new Date()).subtract(this.days, 'days').calendar() }
      </p>
    );
  }
}

index.html

<!DOCTYPE html>
<html dir="ltr" lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
  <title>Stencil Starter App</title>
  <script src="build/app.js"></script>
</head>
<body>

  <days-ago days="15"></days-ago>

</body>
</html>

Output to the browser:

15 days ago, the date was: 08/09/2017

@zwacky
Copy link

zwacky commented Aug 27, 2017

@andreasbhansen did you mean to add a <script src="build/vendor.js"></script> or similar?

@ansarizafar
Copy link
Author

I wanted to ask How can we create a separate vendor/common bundle for external libraries.

@zwacky
Copy link

zwacky commented Aug 27, 2017

@ansarizafar as far as I understand the current state, this is not automagically supported yet. You may want to check out the discussion in the referenced issue.

@andreasbhansen
Copy link

@zwacky Hm, didn't add anything like that to make it work. What I posted is exactly what I used to make it work, and render the output.
However, the post you reference (and the Stencil website) states that due to being async it might not always work – that's rough! The build/vendor.js approach would of course be way better.

I hope Stencil will come with a CLI command for generating a vendor bundle based on import statements in the .tsx files. stencil g vendors 👍

@jgw96
Copy link
Contributor

jgw96 commented Aug 29, 2017

Hello all! We are working on some ideas for this. For now in the alpha, your best bet is probably to use script tags.

@jgw96 jgw96 added the feature label Aug 29, 2017
@zwacky
Copy link

zwacky commented Aug 29, 2017

works. created a vendor.bundle.js file that is included in the index.html via script tags.

caveat: for now you can't use those imports inside of the stencil project source, because the build process isn't up for this, yet.

e.g. I'm using firebase and I can't use the firebase from import * as firebase from 'firebase/app'; rather I need to use window.firebase.

edit: the watch process gets stuck at prerender index html started ...

@psyrendust
Copy link

@zwacky I get the same thing with trying to import mapboxgl from 'mapbox-gl';. Every once in a while I'll get the following in the console.

[40:17.8]  changed file: my-map.tsx
[40:17.8]  rebuild, dev mode, started ...
[40:17.8]  compile started ...
[40:18.7]  compile finished in 864 ms

[ ERROR ]  typescript: src/components/my-map.tsx, line: 1
           Cannot find module 'mapbox-gl'.

      L1:  import mapboxgl from 'mapbox-gl';
      L2:  import { Component, Prop, State } from '@stencil/core';

[40:18.7]  rebuild failed, watching for changes... in 876 ms

But most of the time it's:

[40:22.8]  changed file: my-map.tsx
[40:22.8]  rebuild, dev mode, started ...
[40:22.8]  compile started ...
[40:23.7]  compile finished in 879 ms
[40:23.7]  bundle styles started ...
[40:23.7]  bundle modules started ...
[40:23.7]  bundle styles finished in 3 ms
[40:24.9]  bundle modules finished in 1.28 s
[40:24.9]  prerender index html started ...

And the process never continues prerender index html finished and rebuild finished, watching for changes....

@davidmpaz
Copy link

It seems that some bundling mechanism is starting to be needed :) hope it is not reinvented.

Don't know how could Webpack fit here. Even when on Polimer Submit was stated that separation from it (was desired also).

Looking forward for a solution as I have same requirements.

@jgw96
Copy link
Contributor

jgw96 commented Sep 8, 2017

Hello all! Just an update on this: with chrome and safari now shipping es modules, we are currently looking into using them to achieve this functionality, with a fallback for browsers that do not support it. This will also allow us to do cool things such as ship a completely ES2015 version of stencil as an ES module and then still ship an es5 version to browsers which do not support es modules.

@kylecordes
Copy link

@jgw96 Here is a technical tip that you are probably already aware of, but I will mention it just in case.

There is a lot of motivation when writing something like this, to write its source code as numerous files/modules. But in deployment, it is unpleasant to consume and distribute something that arrives in the form of highly numerous files. Further, there is overhead in loading those in a browser (even with HTTP 2 push), linking them together, optimizing them for payload size, etc. With a highly module code base, all those exports and imports really add up.

The Angular team had this challenge and came up with a great solution. They internally develop Angular as numerous small files/modules. Then their build process yields a "flat JavaScript module" for each major chunk of Angular. The result is a single file/single ES module, smaller than the total of its many-file "source", but which preserves the same semantics of use from the outside as if it had arrived as numerous small files. Rollup can do this ES2015->ES2015 module bundling, though I don't know if that is that tool Angular uses.

@psyrendust
Copy link

I'm not familiar with Angular's bundling process, but I am with Aurelia's. I believe that they take a similar approach. They do the following:

  1. Parse local src files for all import statements.
  2. Separate local imports (import foo from './...') from those that are npm installed.
  3. Inline the contents of the local imports.
  4. Prune the import statements for the local imports.
  5. Write back only the import statements that are npm installed.

You can see it in the build file for router's build task. This leaves you with 1 file that has a bunch of ES6 exports https://github.com/aurelia/router/blob/master/dist/aurelia-router.js.

They also use cleanGeneratedCode() during a babel transpile to generate the environment specific builds. cleanGeneratedCode() uses some knarly RegExp to pull out the duplicate _classCallCheck methods that get genereated by babel for each module.

@kylecordes
Copy link

@psyrendust That sounds like it accomplishes something similar to what I was describing; but I heartily recommend achieving it using something like Rollup if at all possible. Homegrown code-manipulating-code is a recipe for a long series of edge cases, bugs, and distraction from the main goals of the project.

@psyrendust
Copy link

I totally agree. I thought their implementation was very fragile.

On a side-note, I'd be interested in helping out with the project. PM me if you'd like me to help with anything.

@selcukkutuk
Copy link

selcukkutuk commented Sep 10, 2017

I'm trying to add the axios library. But, I get an error:

import { Component, Prop, State } from '@stencil/core';
import axios from 'axios';

axios.get('https://jsonplaceholder.typicode.com/users');

//****
[08:23.7]  changed file: ornek-sayac.tsx
[08:23.7]  rebuild, dev mode, started ...
[08:23.8]  compile started ...
[08:26.1]  compile finished in 2.39 s
[08:26.1]  bundle styles started ...
[08:26.2]  bundle modules started ...
[08:26.2]  bundle styles finished in 9 ms
[08:26.9]  bundle modules finished in 795 ms

[ ERROR ]  bundling: ...:/sample-app/node_modules/axios/lib/adapters/http.js, line: 4
A module cannot import itself
L3:  var utils = require('./../utils');
L4:  var settle = require('./../core/settle');
L5:  var buildURL = require('./../helpers/buildURL');
[08:27.0]  rebuild failed, watching for changes... in 3.26 s

What am I doing wrong?

@adamdbradley
Copy link
Contributor

Internally all of the bundles are using rollup. So when you import moment in a component, it'll bring it into the file for you.

The area for improvement here is that components can share the same imports, and we can do this through ES module imports. This is on our todo list.

#162

@VicJerUk
Copy link

VicJerUk commented Mar 9, 2021

This seems to be a common problem I see. I am trying to add a third-party library to my component and it blows up. For some reason it thinks its running in node environment rather than browser when I run the stencil start. Only way I managed to avoid it is by using the script tags and pulling library from CDN... Bit rubbish if you ask me.

@bitflower
Copy link
Contributor

@VicJerUk I have solved a lot of these issue with rollup plugins (specifically alias and replace).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests