This will explain how to use can-ssg
in its current state once
it has been migrated to its own npm library called can-ssg
- Install dependencies (will be required once
can-ssg
is migrated to a library)
$ npm i -D can-ssg # Installs can-ssg
When using can-ssg
, you'll have to use a specific version of can-stache-element
(for now):
$ npm i can-stache-element@git+ssh://[email protected]/canjs/can-stache-element#allow-static-inert-extended
File summary
/assets/ - application assets: imgs, svgs, favicons, etc
/index.html - entry point html file for application
/main.js - entry point js file for `can-stache-element` app
/postbuild.js - post ssg static files instructions
/prebuild.js - pre ssg static files instructions
/ssg.json - ssg configurations
- Create
ssg.json
file:
At the root of your project, create ssg.json
:
{
"assets": ["assets"],
"defaultServerMode": "ssg",
"defaultEnv": "dev",
"environments": {
"dev": {
"dist": {
"basePath": "dev",
"static": "static",
"assets": "",
"entryPoint": "index.html"
},
"staticBaseUrl": "http://localhost:8080",
"entryPoint": "index.html"
},
"prod": {
"prebuild": "prebuild.js",
"postbuild": "postbuild.js",
"dist": {
"mainTag": "<script src=\"/dist/bundles/can-stache-element-ssr/main.js\" main></script>",
"basePath": "prod",
"static": "static",
"assets": "",
"entryPoint": "index.html"
},
"staticBaseUrl": "http://localhost:8080",
"entryPoint": "index.html",
"serveFromDist": true
}
},
"routes": []
}
Summary of each of these properties are listed in README.md
- Create
/assets/
directory
At the root of your project, create /assets/
directory:
This will be an empty directory for now
- Create
index.html
file:
At the root of your project, create index.html
file:
<!DOCTYPE html>
<head>
<title>CanJS and StealJS</title>
</head>
<body>
<can-app></can-app>
<script src="/node_modules/steal/steal.js" main></script>
</body>
This will be the entry point html file for your can-stache-element
application.
- Create
main.js
file:
At the root of your project, create main.js
file:
import StacheElement from "can-stache-element"
import { ssgDefineElement, ssgEnd } from "can-ssg"
class MyApp extends StacheElement {
static view = `
<h1>Hello World</h1>
`
}
// A wrapped `customElements.define` function
// required for `can-ssg` to function properly
ssgDefineElement("can-app", MyApp)
// Required to be called at the end of your `main.js` file
ssgEnd()
This will be the entry point html file for your can-stache-element
application.
- Create
prebuild.js
file:
At the root of your project, create prebuild.js
file:
const stealTools = require("steal-tools")
const path = require("path")
const { getEnvConfiguration } = require("can-ssg")
const envConfiguration = getEnvConfiguration("prod")
const distDir = path.join("dist", envConfiguration.dist.basePath)
main()
async function main() {
await stealTools.build(
{},
{
bundleSteal: true,
dest: path.join(distDir, "dist"),
},
)
}
This will create production bundles of your application which includes steal.js
in the bundle.
- Create
postbuild.js
file:
At the root of your project, create postbuild.js
file:
const path = require("path")
const { getEnvConfiguration, getEnvAssets, getEnvRoutes, getEnvironment } = require("can-ssg")
const { copy } = require("fs-extra")
const environment = getEnvironment()
const envConfiguration = getEnvConfiguration("prod")
const distDir = path.join("dist", envConfiguration.dist.basePath)
main()
async function main() {
const promises = []
// Read paths to generate static pages
const routes = getEnvRoutes(environment)
const staticPath = path.join(distDir, envConfiguration.dist.static)
// `steal-tools` prefixes where bundles are created with "dist/bundles"
// This doesn't appear to be customizable,
// you can change the path to where this directory will be created, but it must start with "dist/bundles"
const bundlePath = path.join(distDir, "dist/bundles")
// Copy `steal-tools` bundles to each static page directory
// This is required since each page expected a relative path to the bundle
for (const route of routes) {
const staticBundlePath = path.join(staticPath, route, "dist/bundles")
promises.push(copy(bundlePath, staticBundlePath))
}
const baseAssetsDistPath = envConfiguration.dist.assets ? path.join(distDir, envConfiguration.dist.assets) : distDir
const baseStaticAssetsDistPath = envConfiguration.dist.assets ? path.join(staticPath, envConfiguration.dist.assets) : staticPath
const assets = getEnvAssets(environment)
// Copy assets to each static page directory
for (const assetPath of assets) {
const assetsDistPathInDist = path.join(baseAssetsDistPath, assetPath)
const staticAssetsDistPathInDist = path.join(baseStaticAssetsDistPath, assetPath)
promises.push(copy(assetsDistPathInDist, staticAssetsDistPathInDist))
}
await Promise.all(promises)
}
This will copy dist
files into various directories to support access to bundles / assets for ssg static pages.
This walkthrough creates two environments:
-
dev - used for local development
$ can-ssg build # this works because `defaultEnv` is set to "dev" in `ssg.json` # or $ can-ssg build --environment dev # or $ SSG_ENVIRONMENT=dev can-ssg build
-
prod - used to deploy
$ can-ssg build --environment prod # or $ SSG_ENVIRONMENT=prod can-ssg build
When serving, there are 2 modes:
-
spa - used for rapid development
-
ssg - uses ssg static files from dist that will hydrate into live applications
For each serve mode, you'll have to choose an environment: dev or prod
Depending on which environment and server mode, you might have to build before serving:
- spa + dev - doesn't require a build
$ can-ssg serve --environment dev --serverMode spa
# or
$ SSG_ENVIRONMENT=dev SERVER_MODE=spa can-ssg serve
- ssg + dev - requires require a build
$ can-ssg serve --environment dev --serverMode ssg
# or
$ SSG_ENVIRONMENT=dev SERVER_MODE=ssg can-ssg serve
- spa + prod - requires require a build
$ can-ssg serve --environment prod --serverMode spa
# or
$ SSG_ENVIRONMENT=prod SERVER_MODE=spa can-ssg serve
- ssg + prod - requires require a build
$ can-ssg serve --environment prod --serverMode ssg
# or
$ SSG_ENVIRONMENT=prod SERVER_MODE=ssg can-ssg serve
You can use just about anything to serve the ssg prod pages. Given this walkthrough's ssg.json, you could also serve using http-server
:
$ npx http-server dist/prod/static