I'd like to use chart.js in an aurelia project, but I'm getting errors. How do I add 3rd party node packages to an aurelia app?
I'm using aurelia-cli, BTW
Here's what I've done
npm install --save chart.js
In aurelia.json I added the following
"dependencies": [
...,
{
"name": "chart.js",
"path": "../node_modules/chart.js/dist",
"main": "Chart.min.js"
}
]
In app.html I then add the line
<require from="chart.js"></require>
But, I get the error:
vendor-bundle.js:1399 Unhandled rejection Error: Load timeout for modules: template-registry-entry!chart.html,text!chart.html
I've tried various things like injecting the Chart into the app.html
// DIDN'T WORK :-(
// app.js
import {inject} from 'aurelia-framework';
import {Chart} from 'chart.js';
export class App {
static inject() { return [Chart]};
constructor() {
this.message = 'Hello World!';
}
}
And, then, in app.html, I added the following require statement
<require from="Chart"></require>
HERE'S THE SOLUTION
You can checkout a working example here. Initially, I thought you had to use the aurelia-chart module, however, it's very difficult to use, and so, I'd recommend you just use Chart.JS package instead. Here's how to incorporate the chart.js module into your Aurelia app:
npm install --save chart.js
In aurelia.json add the following line to the prepend section
"prepend": [
...,
"node_modules/chart.js/dist/Chart.min.js"
],
In the app.js file (or any other model-view file), add the line
import {Chart} from 'node_modules/chart.js/dist/Chart.js';
For, example, if you wanted to display a chart on the home page:
// app.js
import {Chart} from 'node_modules/chart.js/dist/Chart.js';
export class App {
...
}
And that's it!
1. Problem with require
First of all, don't use <require from="Chart"></require> in your app.html project. That is the source of your error message, since it's trying to load an Aurelia module and chart.js is not an Aurelia module (view/viewmodel) in your source code.
2. Alternate import syntax
Skip the inject lines in app.js, but try one of the following (try them one at a time) in either app.js or in each module you'll be using Chart. One of these imports is likely to work.
import { Chart } from 'chart.js';
import * from 'chart.js';
import 'chart.js';
3. Legacy prepend
If none of the above works, import it as a legacy repo using the prepend section of aurelia.json (before the dependencies section) like this:
"prepend": [
// probably a couple other things already listed here...
"node_modules/chart.js/dist/Chart.min.js"
],
Update for Aurelia-Chart: (added for any later viewers)
Since you ended up going with aurelia-chart (by grofit), here's the dependency code for aurelia.json:
"dependencies": [
...,
{
"name": "chart.js",
"path": "../node_modules/chart.js/dist",
"main": "Chart.min.js"
},
{
"name": "aurelia-chart",
"path": "../node_modules/aurelia-chart/dist/amd",
"main": "index",
"deps": ["chart.js"]
}
]
I just got this working with an aurelia cli project and it required some extra modifications.
I used au install chart.js but there is an open issue that states it is not intelligent enough yet to add references to package dependencies.
To make things work I added the following to my aurelia.json dependencies:
"moment",
"chartjs-color",
"chartjs-color-string",
{
"name": "chart.js",
"main": "src/chart.js",
"path": "../node_modules/chart.js",
"deps": ["chartjs-color", "moment"]
},
{
"name": "color-convert",
"path": "../node_modules/color-convert",
"main": "index"
},
{
"name": "color-name",
"path": "../node_modules/color-name",
"main": "index"
}
I was then able to import { Chart } from 'chart.js'; in my view model and run the chart.js quick start example from the attached viewmodel lifecycle method.
In the chart.js docs they mention including the minified version can cause issues if your project already depends on the moment library.
The bundled version includes Moment.js built into the same file. This version should be used if you wish to use time axes and want a single file to include. Do not use this build if your application already includes Moment.js. If you do, Moment.js will be included twice, increasing the page load time and potentially introducing version issues.
This solution may help if you are in that position.
Related
I followed the instructions in antd-mobile usage link for importing antd-mobile using babel-plugin-import, however when I use an import of the format:
import {Card as CardMobile, WhiteSpace} from 'antd-mobile';
This warning still appears in the browser console log:
You are using a whole package of antd-mobile, please use https://www.npmjs.com/package/babel-
plugin-import to reduce app bundle size.
I can resolve the warning by using manual import references:
import WhiteSpace from 'antd-mobile/lib/white-space';
import 'antd-mobile/lib/white-space/style/css';
import CardMobile from 'antd-mobile/lib/card';
import 'antd-mobile/lib/card/style/css';
but I was hoping to use the less verbose, non-manual form.
Here's the plugin configuration settings in .babelrc:
"plugins": [
"#babel/proposal-class-properties",
"#babel/plugin-syntax-dynamic-import",
"#babel/transform-runtime",
["import", { "libraryName": "antd", "libraryDirectory": "lib"}, "antd"],
["import", { "libraryName": "antd-mobile", "libraryDirectory": "lib"}, "antd-mobile"],
["babel-plugin-webpack-alias", { "config": "./webpack.config.common.js" }]
],
Here are some of the package versions from package.json (let me know if any other package versions are needed):
"antd-mobile": "2.3.4",
"babel-plugin-import": "1.11.2",
"#babel/core": "7.2.2",
import {Card as CardMobile, WhiteSpace} from 'antd-mobile';
here you are accessing the whole package. we need to split it down.
import Card as CardMobile from 'antd-mobile/Card';
import WhiteSpace from 'antd-mobile/WhiteSpace';
now we are importing only the specific things, what we will be using in our file.
Use modularized antd-mobile From antd-mobile site metioned How does it work?
Go to the target page, you will see (sorry for I can't post image directly for now):
snapshot, click to check out
you might still be using webpack#1.x or have a wrong webpack config which can't support tree shaking.
I currently have a large private NPM library which is being consumed by several other teams' apps across the business. At the moment the library is being published as one large single file (like the main lodash file) but this is causing application bundle size to be bloated as some of the applications don't need a large chunk of what is in the library.
So at the moment the apps are importing something like this
import { SomeReactComponent, someHelperFunction } from 'my-private-library';
What I want to achieve is the library published with individual modules similar to how Lodash, so the above would become:
import SomeReactComponent from 'my-private-library/lib/SomeReactComponent';
import someHelperFunction from 'my-private-library/lib/someHelperFunction';
I can get Webpack to output output the library in this format using multiple entry points, but what I can't get to work is getting Webpack to split out shared dependencies of each of those modules. So say the files look something like this:
src/SomeReactComponent.jsx
import React from 'react'
import SOME_CONST_STRING from '../constants';
const SomeReactComponent = () => {
return (
<div>You are using {SOME_CONST_STRING}</div>
);
}
export default SomeReactComponent;
src/someHelperFunction
import SOME_CONST_STRING from '../constants';
export default function someHelperFunction() {
return `This is just an example of ${SOME_CONST_STRING}`;
}
My Webpack is outputting the individual files, but it's not splitting out common code in a way that an app can consume the library. So notice above the SOME_CONST_STRING which is imported in each of the modules, Webpack is putting this code in both of the exported files.
My Webpack config looks a bit like this (removed other setting for brevity)
module.exports = {
entry: {
SomeReactComponent: './src/SomeReactComponent',
someHelperFunction: './src/someHelperFunction',
},
output: {
path: './lib',
library: 'MyPrivateLibrary'
libraryTarget: 'umd',
filename: '[name].js'
}
// removed other setting for brevity
}
I have tried using the splitChunks optimization setting like this
module.exports = {
entry: {
SomeReactComponent: './src/SomeReactComponent',
someHelperFunction: './src/someHelperFunction',
},
output: {
path: './lib',
library: 'MyPrivateLibrary'
libraryTarget: 'umd',
filename: '[name].js'
},
optimization: {
splitChunks: {
chunks: 'all',
},
},
// removed other setting for brevity
}
which does chunk the code, but when I try to use the library in an app after doing this I get errors along the lines of (ERROR in TypeError: __webpack_require__(...) is not a function).
My question is can anyone see what I'm doing wrong? Is what I'm trying to achieve even possible with Webpack? Are there any example out there (as I can't find any) on how to do this?
Apologies for the example code, as my library is private I'm not able to use real-code examples.
Did you get success to achieve what you were trying to achieve in above scenario. I am working on the same use case and was facing similiar issue. After diagnosing it i found it that when we define library then in parsed module webpack add this in this object as window.myWebpackJsonpMyPrivateLibrary in minified main chunk which is undefined. if you remove the library and libraryTarget from webpack then you will not face this issue.
In my case i faced another issue that required chunk(s) are not being loaded when this is used as install dependency in another project.
I'm trying to integrate Stencil and Storybook inside the same project. I've been following this set up guide and this one however one of the steps is to publish the library of components to NPM and that's not what I want.
I have this repo which I've configured with components library (src folder) and with the reviewer of those components with Storybook, which resides in the storybook folder.
The problem is that when I compile the components using Stencil and copy the dist folder inside the Storybook app and import the component nothing renders. Tweaking the configuration using custom head tags I was able to import it correctly however no styles where applied.
When I open the network panel there is some error when importing the component:
And thus the component is present in the DOM but with visibility set to hidden, which I think it does when there is an error.
This is the component au-button:
import { Component } from '#stencil/core';
#Component({
tag: 'au-button',
styleUrl: 'button.css',
shadow: true
})
export class Button {
render() {
return (
<button class="test">Hello</button>
);
}
}
Here is the story my component:
import React from 'react';
import { storiesOf } from '#storybook/react';
import '../components/components.js'
storiesOf('Button', module)
.add('with text', () => <au-button></au-button>)
These are the scripts inside the Storybook app:
"scripts": {
"storybook": "start-storybook -p 9009",
"build-storybook": "build-storybook",
"copy": "cp -R ./../dist/* components"
},
And the workflow is as follows:
Launch storybook
Make changes in the component
Execute build command
Execute copy command
Also, I would like to automate the developer experience, but after I solve this problem first.
Any ideas of what I could be doing wrong?
Sample for this could be found in the repo
https://github.com/shanmugapriyaEK/stencil-storybook. It autogenerates stories with knobs and notes. Also it has custom theme in it. Hope it helps.
I'm using #storybook/polymer and it's working for me really well.
following your example:
import { Component } from '#stencil/core';
#Component({
tag: 'au-button',
styleUrl: 'button.css',
shadow: true
})
export class Button {
render() {
return (
<button class="test">Hello</button>
);
}
}
the story would be:
import { storiesOf } from '#storybook/polymer';
storiesOf('Button', module)
.add('with text', () => <au-button></au-button>)
the scripts in the package.json:
"scripts": {
"storybook": "start-storybook -p 9001 -c .storybook -s www"
},
the storybook config file:
import { configure, addDecorator } from '#storybook/polymer';
const req = require.context('../src', true, /\.stories\.js$/);
function loadStories() {
req.keys().forEach((filename) => req(filename))
}
configure(loadStories, module);
and storybook preview-head.html you have to add to the body the following:
<body>
<div id="root"></div>
<div id="error-message"></div>
<div id="error-stack"></div>
</body>
I've been following this set up guide and this one however one of the steps is to publish the library of components to NPM and that's not what I want.
My reading of those guides is that they're stating “publish to NPM” as a way to have your files at a known URL, that will work most easily for deployment.
Without doing that, you'll need to figure out a different deployment strategy. How will you get the build products – the dist directory and static files – published so that your HTML will be able to reference it at a known URL? By choosing to diverge from the guidelines, that's the problem you have to address manually instead.
Not an insurmountable problem, but there is no general solution for all. You've chosen (for your own reasons) to reject the solution offered by the how-to guides, which means you accept the mantle of “I know what I want” instead :-)
I have a 2 projects which requires each others.
The root-app is run by node. It imports child-app/index.js.
The child-app has a dependency on root-app as well. It needs to import Component.js from it. child-app is never run independently of root-app, it is always imported by the root-app.
root-app:
/Component.js
/index.js
/package.json
child-app:
/index.js
/package.json
So basically the root-app requires the child-app and the child-app requires a component from the root-app.
root-app/index.js:
import ChildApp from 'child-app';
child-app/index.js
import Component from 'root-app/Component';
At the moment, my package.json files look like this:
root-app/package.json
{
"name": "root-app",
"dependencies": {
"child-app": "file:../child-app"
}
}
child-app/package.json
{
"name": "child-app",
"peerDependencies": {
"root-app": "file:../root-app"
}
}
This of course doesn't work and I get an error:
Unable to resolve module 'root-app' from
'root-app/node_modules/child-app/index.js'
So my question, is there any way to have this kind of dependencies working without the need of creating a third project that will work as a "bridge" between those two projects?
Thanks!
You have "name":"root-app" in child-app/package.json. But still, it's better to avoid circular dependencies between packages. You might take a look at the dependency inversion principle to get an idea how to do so.
I used pikaday.js and moment.js in Angular2.
In order to build with 3rd party libraries at Angular2, added script path to angular-cli.json.
I saw what how to build 3rd party library. Link is below.
https://github.com/angular/angular-cli#3rd-party-library-installation
I installed pikaday.js and moment.js.
$ npm install pikaday moment --save-dev
Then, I added scripts path, and css files path to angular-cli.json.
"app": [{
"styles": [
"styles.css",
"../node_modules/pikaday/css/pikaday.css",
"../node_modules/pikaday/css/site.css",
"../node_modules/pikaday/css/theme.css",
"../node_modules/pikaday/css/triangle.css",
],
"scripts": [
"../node_modules/pikaday/pikaday.js"
]
}]
That is success! angular-cli is really useful.
But, I found one problem.
Angular cli output 3rd party css that into html of the page using Angular2.
But there is a page that does not wanna use the library. Because, the page layout style was broken.
So, please tell me how to resolve this problem.
Thank you for any help you can provide.
Edit
I modified my component. below.
import {Component, OnInit, Input, ElementRef, ViewEncapsulation} from '#angular/core';
const pikaday = require('../node_modules/pikaday/pikaday');
const pikadayStyle = require('../node_modules/pikaday/scss/pikaday.scss');
#Component({
selector: '[appDatePicker]',
template: '',
styleUrls: [pikadayStyle],
encapsulation: ViewEncapsulation.None
})
export class DatePickerComponent {
// implement
}
Thank you VadimB.
I'm not sure if my solution can solve your particular problem as it depend how this library is structured inside, but for me this was a solution - I used require module loader;
var app = require('some-non-ES6-library');
Just try this first.
<script>
System.amdRequire();
System.amdDefine();
System.config({
...
});
</script>