Autocomplete and documentation for "imported" p5js

I spent countless hours to get my editor (VSC) to autocomplete P5JS.
This worked only after adding this line to the main script:

import "./p5"

Now everything is accessible only if prefixed by p5, and the editor autocompletion and online documentation finally work.

Also, I’ve read that this importing method is not recommended for some reason, but it’s the only way to get a reasonable coding environment, so I guess I should change it? But then, how do I get the documentation and autocompletion to work?

Hi @atcold,

Welcome to the forum! :wink:

Since you are on VSCode, have you seen this p5js extension?

It says:

p5.vscode helps you create p5.js projects in Visual Studio Code. It also includes autocompletion, a simple tool to browse and install third-party p5 libraries, and the Live Server extension.

Also check this GitHub issue:

And also this:

1 Like

Thank you for your answer.

I did install the p5.vscode extension, and things are much better. I.e. documentation and autocompletion do work for P5JS.

In my current project I’m also using https://unpkg.com/ml-matrix@6.8.0/matrix.umd.js. In order to get Intellisense to work, I believe I need to use some sort of

/// <reference path="…"

syntax, where I’m passing a TS file. Now, I have no idea where to get that.
I’m extremely new to JS and extremely lost.

Edit
Okay, the file lives here https://unpkg.com/ml-matrix@6.8.0/matrix.d.ts. But nothing works. The frustration grows, LOL.

1 Like

If you are using multiple libraries in your project, it’s strongly recommended to use a package manager like NPM (which is a standard in web development).

A quick example of npm (assuming you are on Linux):

$ mkdir p5js-test # creates a new project folder
$ cd p5js-test
$ npm init -y # creates a new project using npm, -y yes to all
$ npm install ml-matrix # install package
$ code . # open VSCode

With that I have instant autocompletion in VSCode because all the packages are located inside a node_modules folder.

1 Like

Isn’t this used for server-side code?
I’m really a newbie…

I’m putting together this demo, which is using a numerical external library, which is not going to be installed on the client.
I would like to be able to access to autocompletion and documentation within the editor (like I’m used to when I’m coding anything in Python).

Thank you again for helping out.

Edit
I’ve downloaded https://unpkg.com/ml-matrix@6.8.0/matrix.d.ts in side the libraries folder and added the following line to the beginning of my script

const mlMatrix = require("./libraries/matrix");

Now VSC autocompletion and documentation work.
I only need to comment out the line before saving, so it does not break the execution.

I’m back using the online interface (without autocompletion or documentation), at least I don’t need to fight VSC. The only thing that’s scary is that I cannot use Git in the online editor.

Edit 2
I’ll try again tomorrow. Today I was too irrational to get it to work.

1 Like

Yes you’re mostly right. NPM installs the packages in a node_modules folder and therefore not adapted to use within a <script> tag in an HTML page. You need to use a bundler (webpack, browserify, grunt…) that packs all the code into js, css and html files.

This guide explains it very well:

But if it’s a small project, don’t bother using npm and webpack for example since it’s quite a setup.

You can check out this Reactjs example

npm install is just a pip install. npm install it at the local folder in default.

https://jonathansum.github.io/ml-matrix_Reactjs_Example/

Code: GitHub - JonathanSum/ml-matrix_Reactjs_Example

Some of the code is from your example.

import { Matrix } from 'ml-matrix';



let V = []
let U = []
let clicked = []
let e_values = [1, 1]
// 2 bases, 2 left-singular vectors, 2 e'evectors
let locked = [false, false, false, false, false, false]
let N = 16
let A = []
const bases = [0, 12]
const norm = 50
let s_values = [[norm, 0], [0, -norm]]
let svd

const red = '#fb8072'
const green = '#b3de69'
const orange = '#fdb462'
const blue = '#80b1d3'
const blue_orange = [blue, orange]



const draw = (ctx,) => {

    const w = ctx.width
    const h = ctx.height

    const cx = w / 2;
    const cy = h / 2;
    for (let n = 0; n < N; n++) {
        V[n] = [];
        V[n][0] = norm * Math.cos(n * 2 * Math.PI / N);
        V[n][1] = norm * Math.sin(n * 2 * Math.PI / N);
        U[n] = [...V[n]];
    }
    A[0] = [1, 0]
    A[1] = [0, 1]

    // compute_singular_vectors()


    ctx.beginPath()
    const color_matrix = Matrix.ones(6, 6);


    // vanilla javascript 
    console.log("Starting")
    for (var i = 0; i < 6; i++) {
        for (var j = 0; j < 6; j++) {
            // console.log(i + " " + j);
            // console.log(m1.data[i][j])
            color_matrix.data[i][j] = Math.floor(255 - 42.5 * i)
            ctx.fillStyle = 'rgb(' + Math.floor(255 - 42.5 * i) + ', ' +
                Math.floor(255 - 42.5 * j) + ', 0)';
            ctx.fillRect(j * 25, i * 25, 25, 25);
        }
    }

    // ml-matrix javascript example


    ctx.moveTo(300, 300);
    ctx.font = "30px Arial";

    for (var i = 0; i < 6; i++) {
        for (var j = 0; j < 6; j++) {
            ctx.fillText(color_matrix.data[i][j], j * 200 + 200, i * 200 + 200);
        }
    }



}

80% done. The missing is the button setting.

svd = new mlMatrix.SVD(A)

I don’t see the document allows us to use it in this way.

Do you know how to use it in this way npm that “npm library”?

I followed these instructions, but the autocompletion and documentation do not show up.


image|538x195
image|619x500

I get it to work only if I add import * as mlMatrix from "ml-matrix".

[image|690x162](upload://db0gzczBerFrI4Fgsz7FbBXwGpM.png

Of course, if I try to save with line 1 uncommented, then it does not run.

[image|690x286](upload://yVVvFgz34iWX5bgEVKgiyJPNJ4c.png
Alt-text: script.js:1 Uncaught SyntaxError: Cannot use import statement outside a module.

So, it seems like I need to keep toggling back and forth line 1. This seems a little crazy.
Am I doing anything wrong? Shall I post this question on, say, StackOverflow, since it’s not Processing related?

P.S. Only one image is allowed for new users… If a moderator can add a ! in front we can all see the pictures. Also, up to two links. Jeez… Plz, add two missing )

Check this thread:

Most of the time, when you use npm packages they come with TypeScript types definitions and therefore you get auto completion and other neat features.

For the ml-matrix library, you need to download the .d.ts declaration file and put the path to it at the top of your source file:

///<reference path=" put the filename with path here "/>
1 Like

I did that, but then it works only if I don’t prepend mlMatrix. to all instructions.
I think it’s a lost cause.

When importing via <script src> the package add itself under the name mlMatrix, but the IDE has no clue about this.
Adding import * as mlMatrix from "ml-matrix" makes it work, but breaks the code, if not commented out.

I’ll create an issue on Stack Overflow, since this is not related to Processing.
Thank you again for your time.
I’ll post here the solution if there is any.

1 Like

I’ve created this issue on StackOverflow. Let’s see if there’s a solution.

1 Like

When we use import in JS 2 things happen:

  1. The file becomes a JS module and it needs a <script type=module> to load inside the HTML.
  2. JS checks the import line if a file w/ that exactly path & name exists so it can load it as a module.

As we can note the file “ml-matrix” doesn’t exist.
Instead there are “matrix.js” & “matrix.umd.js”.
However neither is a JS module but just vanilla JS code.

The library’s types is called “matrix.d.ts”.
But to make things worse “matrix.umd.js” is exposed as namespace mlMatrix, while “matrix.d.ts” exposes its main class as Matrix.

It doesn’t seem very feasible to have at the same time types when coding & auto deployment w/o the trouble of manually commenting & uncommenting the line w/ import.
Unless you code some script which automatically do that toggling magic for you.

Anyways, I’ve found a workaround for it.
However you’re gonna need to switch to TypeScript in order to pull that out.

TypeScript automatically skips any import statements when transpiling our code to JavaScript as long as we just use those imports as datatypes and never as the actual thing.

The main workaround are these few lines below:

import * as p5 from "p5";
import {} from "p5/global";

import * as mlmtx from "ml-matrix";

declare var mlMatrix: typeof mlmtx;

After those lines we can freely use mlMatrix as a namespace for the whole “ML-Matrix” library.

And none of those lines will show up at the transpiled JS file!

Check the simple example online at this link:
GoToLoop.GitHub.io/ML-Matrix-P5JS-Template

And visit the repo to download the whole code release:

3 Likes

Breaking links because new users cannot post links… Moderator, plz, edit my posts (this and my previous one).

Hi @GoToLoo, thank you very much for your extensive reply. Let me see if I understand what you’re saying (I think I am still missing a few bits of info).

Still

So, how is that ml-matrix does not exist, yet it fixes autocompletion and documentation?

So, there are three major files (how do we know this? I see many files in this repo).

  1. matrix.js defines the library functions;
  2. matrix.umd.js contains the automatically generated Universal Module Definition (whatever that means);
  3. matrix.d.ts seems to contain the documentation.

How do we learn this? I tried reading that file, but it’s machine generated.

This implies that I will have to…?

I’m not entirely sure what using TypeScript implies.
But I understand that it’s a workaround to get the IDE to read the documentation.

So, if I understand correctly, you created the file sketch.ts, which gets transpiled into sketch.js.
The latter is using P5JS as a module, and uses globalThis.setup and globalThis.draw.
Why not simply using P5JS as a module to begin with? Why is this transpilation necessary?
How is everyone else coding anything in JavaScript? It seems like rather hacky.

Finally, this is your script.ts

<script defer src=https://cdn.JsDelivr.net/npm/p5></script>
<script defer src=https://cdn.JsDelivr.net/npm/ml-matrix></script>
<script type=module src=sketch.js></script>

I don’t see <HTML>, <HEAD>, nor <BODY>. How is this a legal page?
Also, you include ml-matrix and not matrix.umd.js or matrix.d.ts. How is this working?

2 Likes

File “p5.js” (and “matrix.umd.js” as well) isn’t a built-in JS module:
ExploringJS.com/es6/ch_modules.html

(16. Modules)

JavaScript has had modules for a long time. However, they were implemented via libraries, not built into the language. ES6 is the first time that JavaScript has built-in modules.

That’s a workaround to place both setup() & draw() callbacks in the global context so the library “p5.js” can find & invoke them.

The reason why something like function setup() {} won’t work is b/c file “sketch.js” is a JS module.

JS modules got their own global context separated from the browser’s global context!

Formally that’s an illegal HTML file. However browsers have always been very lenient about rules.

But if you care to inspect the generated page of that “Index.html” file you’ll find those missing elements are automatically inserted.

The reason I code such minimum runnable HTML files is for easier reading w/o unnecessary distractions of having so many <tags> all over the place.

Obviously when the time comes to deploy any project for the final users you’d want a legal HTML file.

https://cdn.JsDelivr.net/npm/ml-matrix is a CDN service link:

“ml-matrix” isn’t the name of the file which is actually loaded!

In order to know which file is actually grabbed we have to inspect its “package.json”, given it’s originally hosted as a NodeJS library:
cdn.JsDelivr.net/npm/ml-matrix/package.json

By default the entry “main” determines the downloadable file:

"main": "matrix.js",

However that particular “package.json” file also contains these 2 additional entries:

  "jsdelivr": "matrix.umd.js",
  "unpkg": "matrix.umd.js",

So JsDelivr CDN ends up getting file “matrix.umd.js” when we go to:
https://cdn.JsDelivr.net/npm/ml-matrix

3 Likes
  • Auto-completion & type inference are IDE features.
  • A smart IDE can infer that “matrix.d.ts” is the TS definition file for the folder named “ml-matrix”.
  • However, “ml-matrix” is just that, a folder name, not an actual file to be imported.
  • When that JS file is actually run by a browser that import statement fails!

By looking at its “package.json” file:
cdn.JsDelivr.net/npm/ml-matrix/package.json

{
  "name": "ml-matrix",
  "version": "6.8.0",
  "description": "Matrix manipulation and computation library",
  "main": "matrix.js",
  "module": "src/index.js",
  "jsdelivr": "matrix.umd.js",
  "unpkg": "matrix.umd.js",
  "types": "matrix.d.ts",
  "sideEffects": false,
  "files": [
    "matrix.d.ts",
    "matrix.js",
    "matrix.umd.js",
    "src"
  ],
  1. “matrix.umd.js” is the library’s browser version:
  1. “matrix.js” is the NodeJS module version:
  1. “matrix.d.ts” is the TypeScript definition file for “matrix.js”:

“matrix.d.ts” isn’t a runnable file but merely describes the type definitions for a JS file.

TypeScript is a JS superset language which has to be transpiled to JS in order to run:

As you’ve already noticed, if you keep using JS for your current project, you’ll have to comment out back & forth the import statement so the code is valid to run in a browser.

On the other hand we need a “tsconfig.json” for calling “tsc” to compile the TS files to JS:

In my Atom IDE I have an addon which auto-compiles when I save a TS file.

But I bet Visual Studio should have some addon for that as well.

Although TS has its fill of advanced stuff, coding in it basically involves adding a colon : followed by a datatype when the IDE can’t auto-infer it:

Above parameter matrix was declared as datatype mlmtx.Matrix.
Alternatively we can just say its datatype is any if we’re feeling lazy:
function displayMatrix(matrix: any) {

We can test TypeScript on this link below:

3 Likes

Thank you, @GoToLoop.
I’m in disbelief developing in JS is so painful.