Installations
npm install prember
Developer
ef4
Developer Guide
Module System
Unable to determine the module system for this package.
Min. Node Version
12.* || 14.* || >= 16
Typescript Support
No
Node Version
18.20.3
NPM Version
10.7.0
Statistics
194 Stars
148 Commits
17 Forks
12 Watching
8 Branches
10 Contributors
Updated on 31 Oct 2024
Languages
JavaScript (90.59%)
HTML (7.73%)
Handlebars (1.68%)
Total Downloads
Cumulative downloads
Total Downloads
1,019,511
Last day
-30.6%
679
Compared to previous day
Last week
-4.5%
4,764
Compared to previous week
Last month
17.3%
21,751
Compared to previous month
Last year
3.2%
245,247
Compared to previous year
Daily Downloads
Weekly Downloads
Monthly Downloads
Yearly Downloads
Dependencies
8
Dev Dependencies
41
prember = Pre Render Ember
A progressive static-site generator for Ember
This Ember addon allows you to pre-render any list of URLs into static HTML files at build time. It has no opinions about how you generate the list of URLs.
Features
- 💯100% Ember
- 🚀 Blazing optimized for speed.
- 🚚 Data Agnostic. Supply your site with data from anywhere, however you want!
- 💥 Instant navigation and page views
- ☔️ Progressively Enhanced and mobile-ready
- 🎯 SEO Friendly.
- 🥇 Ember-centric developer experience.
- 😌 Painless project setup & migration.
- 📦 Embroider support
Quick Start
Add these packages to your app:
1ember install ember-cli-fastboot 2ember install prember
And configure some URLs that you would like to prerender:
// In ember-cli-build.js
let app = new EmberApp(defaults, {
prember: {
urls: [
'/',
'/about',
'/contact'
]
}
});
When you do ember build --environment=production
, your built app will include fastboot-rendered HTML in the following files:
/index.html
/about/index.html
/contact/index.html
Explanation
When you build a normal ember app (ember build --environment=production
) you get a structure something like this:
dist/
├── assets
│ ├── my-app-0d31988c08747007cb982909a0b2c9db.css
│ ├── my-app-bdaaa766a1077911a7dae138cbd9e39d.js
│ ├── vendor-553c722f80bed2ea90c42b2c6a54238a.js
│ └── vendor-9eda64f0de2569c64ba0d33f08940fbf.css
├── index.html
└── robots.txt
To serve this app to users, you just need to configure a webserver to use index.html
in response to all URLs that don't otherwise map to files (because the Ember app will boot and take care of the routing).
If you add ember-cli-fastboot to your app, it augments your build with a few things that are needed to run the app within node via fastboot:
dist/
├── assets
│ ├── assetMap.json
│ ├── my-app-0d31988c08747007cb982909a0b2c9db.css
│ ├── my-app-a72732b0d2468246920fa5401610caf4.js
│ ├── my-app-fastboot-af717865dadf95003aaf6903aefcd125.js
│ ├── vendor-553c722f80bed2ea90c42b2c6a54238a.js
│ └── vendor-9eda64f0de2569c64ba0d33f08940fbf.css
├── index.html
├── package.json
└── robots.txt
You can still serve the resulting app in the normal way, but to get the benefits of server-side rendering you would probably serve it from a fastboot server that knows how to combine the JS files and the index.html
file and generate unique output per URL. The downside of this is that your fastboot server is now in the critical path, which increases your ops complexity and is necessarily slower than serving static files.
prember
starts with an app that's already capable of running in fastboot and augments it further. You configure it with a source of URLs to prerender, and it uses Fastboot to visit each one during the build process, saving the resulting HTML files:
dist/
├── _empty.html <--------- A copy of the original index.html
├── about
│ └── index.html <--------- Pre-rendered content
├── assets
│ ├── assetMap.json
│ ├── my-app-0d31988c08747007cb982909a0b2c9db.css
│ ├── my-app-a72732b0d2468246920fa5401610caf4.js
│ ├── my-app-fastboot-af717865dadf95003aaf6903aefcd125.js
│ ├── vendor-553c722f80bed2ea90c42b2c6a54238a.js
│ └── vendor-9eda64f0de2569c64ba0d33f08940fbf.css
├── contact
│ └── index.html <--------- Pre-rendered content
├── index.html <--------- Rewritten with pre-rendered content
├── package.json
└── robots.txt
The resulting application can be served entirely statically, like a normal Ember app. But it has the fast-first-paint and SEO benefits of a Fastboot-rendered application for all of the URLs that you pre-rendered.
Configuring Your Webserver
Your webserver needs to do two things correctly for this to work:
- It should use a file like
about/index.html
to respond to URLs like/about
. This is a pretty normal default behavior. - It should use
_empty.html
to respond to unknown URLs (404s). In a normal Ember app, you would configureindex.html
here instead, but we may have already overwrittenindex.html
with content that only belongs on the homepage, not on every route. This is whyprember
gives you a separate_empty.html
file with no prerendered content.
Options
You pass options to prember
by setting them in ember-cli-build.js
:
// In ember-cli-build.js
let app = new EmberApp(defaults, {
prember: {
urls: [
'/',
'/about',
'/contact'
]
}
});
The supported options are:
urls
: this can be an array or a promise-returning function that resolves to an array. How you generate the list of URLs is up to you, there are many valid strategies. See next section about using a custom url discovery function.enabled
: defaults toenvironment === 'production'
so thatprember
only runs during production builds.indexFile
: defaults to"index.html"
. This is the name we will give to each of the files we create during pre-rendering.emptyFile
: defaults to"_empty.html"
. This is where we will put a copy of your emptyindex.html
as it was before any pre-rendering.requestsPerFastboot
: defaults to1000
. This tells prember how many requests to pass to a single fastboot instance before creating a new one. This can be useful for memory management.
Using a custom URL discovery function
If you pass a function as the urls
option, prember will invoke it like:
1let listOfUrls = await yourUrlFunction({ distDir, visit });
distDir
is the directory containing your built application. This allows your function to inspect the build output to discover URLs.
visit
is an asynchronous function that takes a URL string and resolves to a response from a running fastboot server. This lets your function crawl the running application to discover URLs.
For an example of both these strategies in action, see ./node-tests/url-tester.js
in this repo's test suite.
Using prember in development
In addition to the enabled
option, you can temporarily turn prember
on by setting the environment variable PREMBER=true
, like:
1PREMBER=true ember serve
However, by default ember-cli doesn't understand that it should use a file like about/index.html
to respond to a URL like /about
. So you should do:
1ember install prember-middleware
It's harmless to keep prember-middleware permanently installed in your app, it has no impact on your production application.
When running in development, you will see console output from ember-cli that distinguishes whether a given page was handled by prember vs handled on-the-fly by fastboot:
prember: serving prerendered static HTML for /about <--- served by prember
2017-10-27T05:25:02.161Z 200 OK /some-other-page <--- served by fastboot
Using prember from an addon
Addon authors may declare urls for prember during compilation. To do so, you will want to:
- Add
prember-plugin
to your addon's package.jsonkeywords
array;- Consider also using package.json's
ember-addon
object to configure your addon to runbefore: 'prember'
- Consider also using package.json's
- Define a
urlsForPrember(distDir, visit)
function in your addon's main file;- This function shares an interface with the "custom URL discovery" function, as defined above; and
- Advise your addon's users to install & configure
prember
in the host application.
Addon authors may also get access to urls from prember. To do so, you will want to:
- Add
prember-plugin
to your addon's package.jsonkeywords
array;- Consider also using package.json's
ember-addon
object to configure your addon to runbefore: 'prember'
- Consider also using package.json's
- Define a
urlsFromPrember(urls)
function in your addon's main file;- This function will receive the array of urls prember knows about as the only argument; and
- Advise your addon's users to install & configure
prember
in the host application.
Using prember with Embroider
You can use prember in an Embroider-based build, however you must apply some changes to your ember-cli-build.js
for it to work.
Embroider does not support the postprocessTree
(type all
) hook that this addon uses to implicitly hook into the build pipeline.
But it exposes a prerender
function to do so explicitly.
In a typical Embroider setup, your ember-cli-build.js
will look like this:
1const { Webpack } = require('@embroider/webpack'); 2return require('@embroider/compat').compatBuild(app, Webpack);
For prember to add its prerendered HTML pages on top of what Embroider already emitted, wrap the compiled output with the prerender
function like this:
1const { Webpack } = require('@embroider/webpack'); 2- return require('@embroider/compat').compatBuild(app, Webpack); 3+ const compiledApp = require('@embroider/compat').compatBuild(app, Webpack); 4+ 5+ return require('prember').prerender(app, compiledApp);
Deployment
You shouldn't need to do much special -- just make sure the html files get copied along with all your other files.
If you're using ember-cli-deploy-s3
, you just need to customize the filePattern
setting so it includes .html
files. For example:
1 ENV.s3 = { 2 bucket: 'cardstack.com', 3 region: 'us-east-1', 4 filePattern: '**/*.{js,css,png,gif,ico,jpg,map,xml,txt,svg,swf,eot,ttf,woff,woff2,otf,html}' 5 allowOverwrite: true 6 };
Compared to other addons
There are other ways to pre-render content:
-
ember-prerender depends on having a real browser to do prerendering, which is heavy and complex. It's old and unmaintained.
-
ember-cli-prerender uses Fastboot like we do, but it is not integrated with the build pipeline (so it's harder to make it Just Work™ with things like ember-cli-deploy) and it has stronger opinions about what URLs it will discover, including blueprint-driven sitemap configuration.
-
ember-cli-staticboot is quite similar to this addon, and I didn't realize it existed before I started making this one. I do think
prember
does a better job of integrating the static build output with the existing ember app in a way that requires the minimal webserver configuration.
Contributing
See the Contributing guide for details.
License
This project is licensed under the MIT License.
No vulnerabilities found.
Reason
no dangerous workflow patterns detected
Reason
no binaries found in the repo
Reason
license file detected
Details
- Info: project has a license file: LICENSE.md:0
- Info: FSF or OSI recognized license: MIT License: LICENSE.md:0
Reason
packaging workflow detected
Details
- Info: Project packages its releases by way of GitHub Actions.: .github/workflows/publish.yml:36
Reason
Found 6/9 approved changesets -- score normalized to 6
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
detected GitHub workflow tokens with excessive permissions
Details
- Warn: jobLevel 'contents' permission set to 'write': .github/workflows/plan-release.yml:39
- Warn: jobLevel 'contents' permission set to 'write': .github/workflows/publish.yml:42
- Warn: no topLevel permission defined: .github/workflows/ci.yml:1
- Warn: no topLevel permission defined: .github/workflows/plan-release.yml:1
- Warn: no topLevel permission defined: .github/workflows/publish.yml:1
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/ef4/prember/ci.yml/master?enable=pin
- Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/ef4/prember/ci.yml/master?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/ef4/prember/ci.yml/master?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:40: update your workflow using https://app.stepsecurity.io/secureworkflow/ef4/prember/ci.yml/master?enable=pin
- Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:41: update your workflow using https://app.stepsecurity.io/secureworkflow/ef4/prember/ci.yml/master?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:45: update your workflow using https://app.stepsecurity.io/secureworkflow/ef4/prember/ci.yml/master?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:72: update your workflow using https://app.stepsecurity.io/secureworkflow/ef4/prember/ci.yml/master?enable=pin
- Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:73: update your workflow using https://app.stepsecurity.io/secureworkflow/ef4/prember/ci.yml/master?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:77: update your workflow using https://app.stepsecurity.io/secureworkflow/ef4/prember/ci.yml/master?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/plan-release.yml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/ef4/prember/plan-release.yml/master?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/plan-release.yml:48: update your workflow using https://app.stepsecurity.io/secureworkflow/ef4/prember/plan-release.yml/master?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/plan-release.yml:54: update your workflow using https://app.stepsecurity.io/secureworkflow/ef4/prember/plan-release.yml/master?enable=pin
- Warn: third-party GitHubAction not pinned by hash: .github/workflows/plan-release.yml:58: update your workflow using https://app.stepsecurity.io/secureworkflow/ef4/prember/plan-release.yml/master?enable=pin
- Warn: third-party GitHubAction not pinned by hash: .github/workflows/plan-release.yml:84: update your workflow using https://app.stepsecurity.io/secureworkflow/ef4/prember/plan-release.yml/master?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish.yml:26: update your workflow using https://app.stepsecurity.io/secureworkflow/ef4/prember/publish.yml/master?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish.yml:46: update your workflow using https://app.stepsecurity.io/secureworkflow/ef4/prember/publish.yml/master?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish.yml:47: update your workflow using https://app.stepsecurity.io/secureworkflow/ef4/prember/publish.yml/master?enable=pin
- Warn: third-party GitHubAction not pinned by hash: .github/workflows/publish.yml:53: update your workflow using https://app.stepsecurity.io/secureworkflow/ef4/prember/publish.yml/master?enable=pin
- Info: 0 out of 12 GitHub-owned GitHubAction dependencies pinned
- Info: 0 out of 6 third-party GitHubAction dependencies pinned
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
- Warn: no security policy file detected
- Warn: no security file to analyze
- Warn: no security file to analyze
- Warn: no security file to analyze
Reason
project is not fuzzed
Details
- Warn: no fuzzer integrations found
Reason
branch protection not enabled on development/release branches
Details
- Warn: branch protection not enabled for branch 'master'
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
- Warn: 0 commits out of 28 are checked with a SAST tool
Reason
25 existing vulnerabilities detected
Details
- Warn: Project is vulnerable to: GHSA-whgm-jr23-g3j9
- Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92
- Warn: Project is vulnerable to: GHSA-qwcr-r2fm-qrc7
- Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg
- Warn: Project is vulnerable to: GHSA-wxhq-pm8v-cw75
- Warn: Project is vulnerable to: GHSA-pxg6-pf52-xh8x
- Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275
- Warn: Project is vulnerable to: GHSA-434g-2637-qmqr
- Warn: Project is vulnerable to: GHSA-49q7-c7j4-3p7m
- Warn: Project is vulnerable to: GHSA-977x-g7h5-7qgw
- Warn: Project is vulnerable to: GHSA-f7q4-pwc6-w24p
- Warn: Project is vulnerable to: GHSA-fc9h-whq2-v747
- Warn: Project is vulnerable to: GHSA-qw6h-vgh9-j6wx
- Warn: Project is vulnerable to: GHSA-pfrx-2q88-qq97
- Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h
- Warn: Project is vulnerable to: GHSA-35jh-r3h4-6jhm
- Warn: Project is vulnerable to: GHSA-6vfc-qv3f-vr6c
- Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv
- Warn: Project is vulnerable to: GHSA-9wv6-86v2-598j
- Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6
- Warn: Project is vulnerable to: GHSA-gcx4-mw62-g8wm
- Warn: Project is vulnerable to: GHSA-m6fv-jmcg-4jfg
- Warn: Project is vulnerable to: GHSA-cm22-4g7w-348p
- Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3
- Warn: Project is vulnerable to: GHSA-4vvj-4cpr-p986
Score
3.5
/10
Last Scanned on 2024-11-25
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn MoreOther packages similar to prember
prember-crawler
A web crawler that works with prember to discover URLs in your app
prember-middleware
ember-cli middleware that helps test prember
ember-meta
Setup meta for your Prember/Ember blog to support opengraph, microdata, Facebook, Twitter, Slack etc.
ember-service-worker-prember
An Ember Service Worker plugin that caches the index.html files for each prember route