Setting Up CanJS
Learn how to install CanJS in your environment.
Choosing the right environment
CanJS has a variety of packages, modules, and files ready to meet the needs of any development environment. This section is for people who aren’t sure what they want. The following lists common scenarios and provides links to the guide(s) that most closely satisfy that scenario.
- I just want to play, make a demo, or learn CanJS right now! 👉 Use the ES module bundle or an online code editor.
- I use webpack 👉 Webpack
- I use StealJS 👉 StealJS
- I use Browserify 👉 Browserify
- I want server-side rendering, progressive loading, continuous integration, testing, and a whole lot more 👉 DoneJS
- I want to maximize long term flexibility 👉 Importing individual packages
If this page doesn't have what you need, please ask on the forums or Slack (#canjs channel).
Explanation of different builds
CanJS has a variety of packages, modules, and files ready to meet the needs of any development environment. This section gives technical details on these items.
The individual packages.
CanJS is composed from over 80 individual packages. For example Component is actually the can-component package, housed in its own GitHub repository. The modules within these packages are written in ES5 JavaScript and CommonJS, so they can be imported by webpack, Browserify, StealJS, and a do not require transpiling.
Apps that need long-term flexibility should install these packages directly. Direct installation means you can upgrade a small part of CanJS when needed.
The
can
packageCanJS publishes a can package to npm. It contains:
./can.js
- The main export, imports every CanJS subproject and exports it as a ES named export. For example,can.js
looks like this:export { default as Component } from "can-component"; export { default as restModel } from "can-rest-model"; // ...
Most module loaders setups with tree-shaking (ex: webpack 2 and StealJS 2) use this module. Import named exports from the
can
package like this:import { Component, restModel } from "can";
./core.mjs
- An ESM module with the named exports of each Core package bundled together in a single file. This is useful for examples and prototyping in modern browsers that support ES modules and for real-world apps that use just what is in core CanJS. It's hosted statically onunpkg
and can be downloaded here.You can import directly from the file as follows:
<script type="module"> import { Component } from "//unpkg.com/can@5/core.mjs"; Component.extend({ tag: "my-app", view: `Hello {{name}}!`, ViewModel: { name: { default: "world" } } }); </script>
./core.min.mjs
- A minified version of./core.mjs
../dist/global/core.js
- A JavaScript file that exports acan
object with core named exports on it. Use this if you want to create a demo or example that will work in browsers that do not support ESM../everything.mjs
- An ESM module with named exports of every٭ package bundled together. This is useful for examples and prototyping in modern browsers that support ES modules. It's hosted statically onunpkg
and can be downloaded here.You can import directly from the file as follows:
<script type="module"> import { Component } from "//unpkg.com/can@5/everything.mjs"; Component.extend({ tag: "my-app", view: `Hello {{name}}!`, ViewModel: { name: { default: "world" } } }); </script>
This file is large as it includes nearly every extension to CanJS. Using this module in production, without tree-shaking, is not advised!
./everything.min.mjs
- A minified version of./everything.mjs
../dist/global/everything.js
- A JavaScript file that exports acan
object with every٭ named export. Use this if you want to create a demo or example that will work in browsers that do not support ESM.
Hosted setup options (no download needed)
The following sections show setting up CanJS with scripts hosted online. These are the easiest ways of setting up CanJS for experimentation.
Importing the core ES module bundle
The easiest way to get started with CanJS is to import the bundled ES module from unpkg. This is perfect for demos, examples, or even small apps!
The following HTML
page imports CanJS and uses it to define a custom element:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>CanJS + Modules</title>
</head>
<body>
<my-app></my-app>
<script type="module">
import { Component } from "//unpkg.com/can@5/core.mjs";
Component.extend({
tag: "my-app",
view: `CanJS {{feels}} modules`,
ViewModel: {
feels: { default: "😍" }
}
});
</script>
</body>
</html>
The previous example works in all modern browsers, even Edge! If you want to support older browsers, use the traditional JavaScript bundle or one of the module loader setups (webpack, StealJS).
This build only includes CanJS’s Core and Infrastructure modules. All modules are exported as named exports. For example, if you want the can-ajax infrastructure module, import it as follows:
import { Component, ajax } from "//unpkg.com/can@5/core.mjs";
Component.extend({
tag: "my-app",
view: `
CanJS {{feels}} modules.
The server says: {{messagePromise.value}}
`,
ViewModel: {
feels: { default: "😍" },
messagePromise: {
default: () => ajax({url: "/message"})
}
}
});
If you want an Ecosystem module like can-stache-converters, you can use the Everything ES module bundle, but the everything bundle should not be used in production as it loads every module in CanJS.
Minified core bundle
If you use the core ES module, make sure to switch to
its minified version (//unpkg.com/can@5/core.min.mjs
) in production like this:
import { Component, ajax } from "//unpkg.com/can@5/core.min.mjs";
Component.extend({
tag: "my-app",
view: `
CanJS {{feels}} modules.
The server says: {{messagePromise.value}}
`,
ViewModel: {
feels: { default: "😍" },
messagePromise: {
default: () => ajax({url: "/message"})
}
}
});
NOTE: Every use of
the unminified URL (//unpkg.com/can@5/core.mjs
) must be updated to
the minified version (//unpkg.com/can@5/core.min.mjs
).
Importing multiple modules
The code that uses CanJS doesn't have to be within the HTML
page itself. Instead you can import modules
that import CanJS. The following shows putting components into their own modules:
index.html
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>CanJS + Modules</title> </head> <body> <my-app></my-app> <script type="module" src="./app.mjs"></script> </body> </html>
app.mjs
import { Component } from "//unpkg.com/can@5/core.mjs"; import "./my-greeting.mjs"; import "./my-counter.mjs"; Component.extend({ tag: "my-app", view: `<my-greeting/><my-counter/>`, ViewModel: { feels: { default: "😍" } } });
my-greeting.mjs
import { Component } from "//unpkg.com/can@5/core.mjs"; Component.extend({ tag: "my-greeting", view: `<h1>CanJS {{feels}} modules</h1>`, ViewModel: { feels: { default: "😍" } } });
my-counter.mjs
import { Component } from "//unpkg.com/can@5/core.mjs"; Component.extend({ tag: "my-counter", view: ` Count: <span>{{count}}</span> <button on:click='increment()'>+1</button> `, ViewModel: { count: {default: 0}, increment() { this.count++; } } });
Importing the everything ES module bundle
The core ES module bundle only includes CanJS’s
Core modules. This doesn't include Ecosystem modules like can-stache-converters. The
everything bundle hosted at https://unpkg.com/can@5/everything.mjs
includes every CanJS module (except for can-zone
and ylem
).
The following shows importing and using can-stache-converters from everything.mjs
:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>CanJS + Modules</title>
</head>
<body>
<my-app></my-app>
<script type="module">
import { Component, stache, stacheConverters } from "//unpkg.com/can@5/everything.mjs";
stache.addConverter(stacheConverters);
Component.extend({
tag: "my-app",
view: `
<p>Enter a value: <input on:input:value:to="string-to-any(enteredValue)"/></p>
<p>You've typed a(n) {{enteredType}}</p>
`,
ViewModel: {
enteredValue: "any",
get enteredType(){
return typeof this.enteredValue;
}
}
});
</script>
</body>
</html>
The everything bundle does not include:
- [can-zone] (https://github.com/canjs/can-zone)
- ylem
Online Code Editors
The following are CanJS examples in various online code editors.
Hello World
See the Pen CanJS 5.0 - Counter by Bitovi (@bitovi) on CodePen.
Routing Example
Model Example
StealJS
You can skip these instructions by cloning this example repo on GitHub.
After setting up Node.js and npm, install can
and StealJS from npm:
npm install can@5 steal@2 --save
Next, add the following steal configuration
to your package.json
:
{
"name": "my-canjs-app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "http-server -c-1",
"test": "echo \"Error: no test specified\" && exit 1"
},
"steal": {
"plugins": ["can"]
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"can": "^5.0.0",
"steal": "^2.0.0"
},
"devDependencies": {
"http-server": "^0.11.0"
}
}
Next, create an app.stache
template for your app:
{{! app.stache }}
<h1>{{message}}</h1>
Next, create an index.js
module for your application. Import Component and
your template to say “Hello World”:
// index.js
import { Component } from "can";
import view from "./app.stache";
Component.extend({
tag: "my-app",
view,
ViewModel: {
message: {
default: "Hello World"
}
}
});
Finally, create an index.html
page that loads steal.js
and includes your
<my-app>
component:
<!doctype html>
<title>CanJS and StealJS</title>
<script src="./node_modules/steal/steal.js" main></script>
<my-app></my-app>
Now you can load that page in your browser at one of the addresses the HTTP server showed you earlier (something like http://localhost:8080/). You should see “Hello World” on the page—if you don’t, join our Slack (#canjs channel) and we can help you figure out what went wrong.
Ready to build an app with CanJS? Check out our Chat Guide or one of our [guides/recipes]!
Webpack
You can skip these instructions by cloning the can-5 branch of this example repo on GitHub.
After setting up Node.js and npm, install can
, webpack
(with can-stache-loader) from npm:
npm install can@5 --save
npm install webpack@4 webpack-cli@3 can-stache-loader@2 --save-dev
Next, create an app.stache
template for your app:
{{! app.stache }}
<h1>{{message}}</h1>
Next, create an index.js
module for your application. Import Component
and your template to say “Hello World”:
// index.js
import { Component } from "can";
import view from "./app.stache";
Component.extend({
tag: "my-app",
view,
ViewModel: {
message: {
default: "Hello World"
}
}
});
Next, we will create a webpack.config.js
that enables tree-shaking in development:
const path = require('path');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const webpack = require("webpack");
module.exports = {
entry: './index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
mode: "development",
module: {
rules: [
{
test: /\.stache$/,
use: {
loader: 'can-stache-loader'
}
}
]
},
plugins: [
new webpack.optimize.SideEffectsFlagPlugin(),
new UglifyJSPlugin({
sourceMap: true,
uglifyOptions: { compress: false, mangle: false, dead_code: true }
})
]
};
Next, run webpack from your terminal:
./node_modules/.bin/webpack
Finally, create an index.html
page that loads dist/bundle.js
and includes
your <my-app>
component:
<!doctype html>
<title>CanJS and webpack</title>
<script src="./dist/bundle.js" type="text/javascript"></script>
<my-app></my-app>
Now you can load that page in your browser at one of the addresses the HTTP server showed you earlier (something like http://localhost:8080/). You should see “Hello World” on the page — if you don’t, join our Slack and we can help you figure out what went wrong.
Production build
To build the app to production, create a webpack.config.prod.js
that configures
webpack for a production build:
const path = require('path');
module.exports = {
entry: './index.js',
module: {
rules: [
{
test: /\.stache$/,
use: {
loader: 'can-stache-loader'
}
}
]
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
mode: "production",
rules: [
{
test: /\.stache$/,
use: {
loader: 'can-stache-loader'
}
}
]
};
Next run webpack in your terminal with the production configuration:
./node_modules/.bin/webpack --config webpack.config.prod.js
Now you can load that page in your browser at one of the addresses the HTTP
server showed you earlier (something like http://localhost:8080/). You should
see “Hello World” on the page and the bundle.js
size should be much smaller. If there's a problem,
join our Slack and we can help you figure out what
went wrong.
Ready to build an app with CanJS? Check out our Chat Guide or one of our [guides/recipes]!
Browserify
Unlike webpack and StealJS, Browserify does not support ES Modules (import "module"
) and tree-shaking
natively. Instead, it’s standard practice to import files with CommonJS (require("module")
). Therefore, there are two
commonly used setups:
Using CommonJS to require CanJS’s individual packages
You can skip these instructions by cloning this example repo on GitHub.
Browserify does not support tree-shaking, so the individual packages must be required. This means that instead of importing Component like:
const Component = require("can").Component;
You should do it like:
const Component = require("can-component");
After setting up Node.js and npm, install can-component and Browserify from npm:
npm install can-component --save
npm install browserify --save-dev
Next, create a component:
// index.js
const Component = require("can-component");
Component.extend({
tag: "my-app",
view: `<h1>{{message}}</h1>`,
ViewModel: {
message: {
default: "Hello World"
}
}
});
Next, run Browserify from your terminal:
./node_modules/browserify/bin/cmd.js --debug --entry index.js --outfile dist/bundle.js
Finally, create an index.html
page that loads dist/bundle.js
and includes
your <my-app>
component:
<!doctype html>
<title>CanJS and Browserify</title>
<script src="./dist/bundle.js" type="text/javascript"></script>
<my-app></my-app>
Now you can load that page in your browser at one of the addresses the HTTP server showed you earlier (something like http://localhost:8080/). You should see “Hello World” on the page—if you don’t, join our Slack and we can help you figure out what went wrong.
Using ES Modules to import CanJS’s individual packages using BabelJS
You can skip these instructions by cloning this example repo on GitHub.
Browserify does not support tree-shaking, so the individual packages must be imported. This means that instead of importing Component like:
import { Component } from "can";
You should do it like:
import Component from "can-component";
After setting up Node.js and npm, install can-component and Browserify (with various plugins) from npm:
npm install can-component --save
npm install browserify stringify babelify babel-core babel-preset-env --save-dev
By default, Browserify works with CommonJS modules (with require()
statements).
To use it with ES6 modules (with import
statements), configure the
babelify plugin in your package.json
.
We’ll also include the stringify
configuration for loading can-stache templates:
{
"name": "my-canjs-app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "http-server -c-1",
"test": "echo \"Error: no test specified\" && exit 1"
},
"browserify": {
"transform": [ [ "babelify", { "presets": ["env"] } ] ]
},
"stringify": {
"appliesTo": { "includeExtensions": [".stache"] }
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"can-component": "^4.0.0"
},
"devDependencies": {
"babel-core": "^6.26.0",
"babel-preset-env": "^1.6.0",
"babelify": "^8.0.0",
"browserify": "^16.1.0",
"http-server": "^0.11.0",
"stringify": "^5.2.0"
}
}
Next, create an app.stache
template for your app:
{{! app.stache }}
<h1>{{message}}</h1>
Next, create an index.js
module for your application. Import can-component
and your template to say “Hello World”:
// index.js
import Component from "can-component";
import view from "./app.stache";
Component.extend({
tag: "my-app",
view,
ViewModel: {
message: {
default: "Hello World"
}
}
});
Next, run Browserify from your terminal:
./node_modules/browserify/bin/cmd.js --debug --transform babelify --transform stringify --entry index.js --outfile dist/bundle.js
Finally, create an index.html
page that loads dist/bundle.js
and includes
your <my-app>
component:
<!doctype html>
<title>CanJS and Browserify</title>
<script src="./dist/bundle.js" type="text/javascript"></script>
<my-app></my-app>
Now you can load that page in your browser at one of the addresses the HTTP server showed you earlier (something like http://localhost:8080/). You should see “Hello World” on the page—if you don’t, join our Slack and we can help you figure out what went wrong.
Ready to build an app with CanJS? Check out our Chat Guide or one of our [guides/recipes]!
DoneJS
CanJS is part of the fabulous DoneJS framework. DoneJS is built around CanJS, and adds:
- iOS, Android, and desktop builds
- Server-side rendering (Isomorphic / UniversalJS)
- Progressive loading
- Continuous integration (testing) and continuous deployment
- Code generators
and many other features.
To use CanJS within DoneJS, first install the DoneJS cli:
npm install -g donejs
Then, generate a new app:
donejs add app hello-world --yes
Then go into that application directory:
cd hello-world
And start development by running:
donejs develop
Go to http://localhost:8080/ to see our application showing a default homepage.
We strongly encourage people to go through DoneJS's Quick start guide and then its In-depth guide to get a feel for all of DoneJS's features.
Script tags setups
This section helps guide setups that do not use a module loader like webpack and StealJS, and instead concatenate scripts, often with a tool like Grunt and Gulp, and non-node projects like the Rails Asset Pipeline.
In short, these projects should use the "global" build. That build can be either:
- downloaded at unpkg.com/dist/global/core.js, or
- installed via npm:
and found innpm install can
./node_modules/can/dist/global/core.js
.
With CanJS downloaded or installed, use it to create an index.html
page with a <script>
tag:
<!doctype html>
<title>My CanJS App</title>
<script src="./node_modules/can/dist/global/core.js"></script>
<my-app></my-app>
<script type="text/stache" id="app-template">
<h1>{{message}}</h1>
</script>
<script type="text/javascript">
const template = can.stache.from("app-template");
can.Component.extend({
tag: "my-app",
view: template,
ViewModel: {
message: {
default: "Hello World"
}
}
});
</script>
This build only includes CanJS’s Core and Infrastructure modules and all of CanJS’s named exports are available on the can object. For example, if you want the can-ajax infrastructure module, use it like can.ajax
:
can.Component.extend({
tag: "my-app",
view: `
CanJS {{feels}} modules.
The server says: {{messagePromise.value}}
`,
ViewModel: {
feels: { default: "😍" },
messagePromise: {
default: () => can.ajax({url: "/message"})
}
}
});
If you want to use Ecosystem modules, you can use ./node_modules/can/dist/global/everything.js
. However,
this file is quite large and shouldn't be used in production so you will want to make your own custom version of
everything.js
containing only the modules you need. Unfortunately, we haven't posted instructions on how to do this yet, even though it’s relatively easy. Please tell us on
Slack to hurry up and do it already!
Hosted traditional <script>
tags setups
If you support older browsers that do not support modules (Internet Explorer 11),
the following sections detail detail how to use hosted JavaScript files work with traditional <script>
tags.
If you only support browsers that do support modules please follow the Importing the core ES module bundle with module scripts setup.
Including the core JavaScript bundle
If you want your demo, example, or small app to work in browsers that do not support ES modules, then you can use the CDN hosted JavaScript bundle on unpkg.
The following HTML
page includes CanJS and uses it to define a custom element:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>CanJS + Modules</title>
</head>
<body>
<my-app></my-app>
<script src="//unpkg.com/can@5/dist/global/core.js"></script>
<script>
can.Component.extend({
tag: "my-app",
view: `CanJS {{feels}} modules`,
ViewModel: {
feels: { default: "😍" }
}
});
</script>
</body>
</html>
This build only includes CanJS’s Core and Infrastructure modules and all of CanJS’s named exports are available on the
can
object. For example, if you want the can-ajax infrastructure module, use it like can.ajax
:
can.Component.extend({
tag: "my-app",
view: `
CanJS {{feels}} modules.
The server says: {{messagePromise.value}}
`,
ViewModel: {
feels: { default: "😍" },
messagePromise: {
default: () => can.ajax({url: "/message"})
}
}
});
If you want an Ecosystem module like can-stache-converters, you can use the everything JavaScript bundle, but the everything bundle should not be used in production as it loads every module in CanJS.
Including the everything JavaScript bundle
The core JavaScript bundle only includes CanJS’s
Core modules. This doesn't include ecosystem modules like can-stache-converters. The everything bundle hosted at https://unpkg.com/can@5/everything.mjs
includes every CanJS module (except for can-zone and ylem.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>CanJS + Modules</title>
</head>
<body>
<my-app></my-app>
<script type="module">
import { Component, stache, stacheConverters } from "//unpkg.com/can@5/everything.mjs";
stache.addConverter(stacheConverters);
Component.extend({
tag: "my-app",
view: `
<p>Enter a value: <input on:input:value:to="string-to-any(enteredValue)"/></p>
<p>You've typed a(n) {{enteredType}}</p>
`,
ViewModel: {
enteredValue: "any",
get enteredType(){
return typeof this.enteredValue;
}
}
});
</script>
</body>
</html>
The everything bundle does not include:
Advanced Setup Recommendations
The following are suggestions to advanced users to maximize maintainability.
Installing individual packages
To maximize flexibility, we recommend installing and importing individual packages and modules
instead of the named exports from the can
package.
For example, instead of importing named exports from the can
module like:
import { Component, DefineMap } from "can";
These packages should be individually installed:
npm install can-component can-define
And they should be imported as follows:
import Component from "can-component";
import DefineMap from "can-define/map/map"
CanJS’s individual packages are released independently of one another. This allows
you to update one package without having to upgrade all the other ones when a new can
package is published.
You can create your own "can"
module or package by importing and exporting
the CanJS packages and modules as named exports.
For example, after installing the packages you need, you can create my-can.js
that looks like
// my-can.js
export { default as Component } from "can-component";
export { default as restModel } from "can-rest-model";
// ...
And then import the named exports from "my-can":
import { Component, restModel } from "./my-can";
Prerequisites
The following sections detail how to install prerequisites common to some of the setups above.
Node.js and npm
Many of the following sections rely on Node.js and npm installed. Please follow these steps to get Node.js, npm, and a local file server installed.
First, go through npm’s guide to installing Node.js and npm. If you’re new to development, that page has additional resources for learning about Node.js, npm, using a command-line terminal, and more.
Next, create a new directory on your computer and navigate to that directory in your terminal.
In your terminal, create a new package.json:
npm init -y
Next, install http-server (so you can load the files we create):
npm install http-server --save-dev
Next, add a start script to run the
HTTP server. Add the following line to your package.json
:
{
"name": "my-canjs-app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "http-server -c-1",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"http-server": "^0.11.0"
}
}
Last, start the HTTP server from your terminal:
npm start
When the server starts, it’ll tell you the addresses you can open in your browser to see your project. They will be similar to http://localhost:8080/.
Next, you can choose to use StealJS, webpack, or Browserify to load your project.
IE11 Support
CanJS 4+ is compatible with Internet Explorer 11 with a few caveats that are discussed below.
CanJS uses Promises, which are not supported in IE11. A Promise polyfill such as the one in core-js or the many others available on NPM can be used to enable Promise support in any environment or setup.
If using StealJS 1.x, a promise polyfill is included by default. With StealJS 2.x, a promise polyfill can be added by using the steal-with-promises.js
or the bundlePromisePolyfill
build option.
The ecosystem packages can-define-backup and can-observe use other features that are not fully supported by IE11.
can-define-backup uses WeakMap, and although WeakMap
is supported in IE11, there are issues with using sealed objects as keys in WeakMaps. can-define-backup can be used in IE11 as long as the DefineMap being backed up is not sealed, or a polyfill such as the one in core-js is used.
can-observe is based on the Proxy object, which is not supported in IE11 and cannot be polfyilled.