Getting started
Integrating into your app
BigPipe has two parts: this PHP library builds the responses, and the npm package
bigpipe-util applies them in the browser. Install both, start the
browser part in your entrypoint and print the BigPipe script at the end of your pages.
Requirements
- PHP 8.0 or higher
- A bundler, such as webpack or Vite.
bigpipe-utilships ES modules and CommonJS and doesn't depend on a specific bundler.
1. Install the packages
composer require richarddobron/bigpipe
npm install bigpipe-utilUse the same major and minor version of both, e.g. 2.1.x of bigpipe-util works with 2.1.0 of this library.
2. Set up the entrypoint
In your entrypoint (e.g. resources/js/app.js), start the Primer, which makes links and forms with rel asynchronous,
and tell BigPipe how to load your modules. The server refers to them by name, e.g. $response->call('MyModule'), and
BigPipe calls the loader to get the module, its default export.
webpack
import Primer from 'bigpipe-util/dist/Primer';
import { setModuleLoader } from 'bigpipe-util/dist/ModuleRegistry';
Primer();
setModuleLoader(modulePath => require('./' + modulePath).default);Vite
import Primer from 'bigpipe-util/dist/Primer';
import { setModuleLoader } from 'bigpipe-util/dist/ModuleRegistry';
Primer();
// Eager, because modules are called synchronously. The entrypoint itself is excluded.
const modules = import.meta.glob(['./**/*.js', '!./app.js'], { eager: true });
setModuleLoader(modulePath => modules[`./${modulePath}.js`]?.default);Names are loaded relative to the entrypoint, so MyModule is resources/js/MyModule.js and Admin/Panel is
resources/js/Admin/Panel.js. The modules of bigpipe-util that the server refers to are resolved automatically.
Vite needs an alias for the events module that dialogs use, and a defined __DEV__ shows debug messages. Both are
described in the bigpipe-util guide.
3. Print the BigPipe script
At the end of the page, print the script that sends the pagelets and the modules required while the page was rendered to the browser:
<?= \dobron\BigPipe\BigPipe::render() ?>The script runs where it is printed and needs the entrypoint to be loaded by then: add the entrypoint with a classic
<script src> before it, in the <head> or at the end of the <body>. A <script type="module">, which is what Vite
adds by default, is deferred until the whole page is parsed. If your entrypoint is a module, render the inline scripts of
BigPipe as module scripts too. They run in the order of the document, after the entrypoint:
<?php \dobron\BigPipe\BigPipe::setScriptType('module'); ?>
<script type="module" src="/build/app.js"></script>
...
<?= \dobron\BigPipe\BigPipe::render() ?>Pagelets are then displayed once the page has been parsed instead of while it streams. Without pagelets you can also print only the modules, once the page is parsed:
<script>
document.addEventListener('DOMContentLoaded', function () {
(new (require("bigpipe-util/dist/ServerJS"))).handle(<?=json_encode(\dobron\BigPipe\BigPipe::jsmods())?>);
});
</script>With a nonce-based Content Security Policy, set the nonce of the request before rendering. nonceAttribute() and
BigPipe::render() add it to the inline scripts, and BigPipe::render() also defines it as the CSPNonce module, from
which the browser part adds it to the stylesheets and scripts of the pagelets:
\dobron\BigPipe\BigPipe::setNonce($cspNonce);Only the page script defines the nonce, AsyncResponse never does: the page keeps the nonce of its own policy, also
when later requests have nonces of their own.
4. Call your first module
A module is a default export: a function, a class or an object.
export default class MyModule {
init(...args) {
console.log('Hello world!', args);
}
}Call it from PHP, with any arguments:
<?php
$response = new \dobron\BigPipe\AsyncResponse();
$response->call('MyModule', 'init', [
'first argument',
'second argument',
]);
$response->send();send() prints the response and ends the script. To call a module when the page has loaded, call it on the page
instead, before the script of step 3 is printed: \dobron\BigPipe\BigPipe::page()->call('MyModule', 'init').
5. Make an element asynchronous
Add rel="async" to a link or a form, answer with an AsyncResponse and BigPipe applies it:
<a href="#" ajaxify="/ajax/remove.php?id=123" rel="async">Remove</a><?php
$response = new \dobron\BigPipe\AsyncResponse();
$response->remove('#item-' . (int) $_GET['id']);
$response->send();6. Pipeline a part of the page
A pagelet is an independent part of the page. The page is sent with its empty placeholder, and the content, CSS and JavaScript follow in the script from step 3:
<?php
use dobron\BigPipe\Pagelet;
$feed = (new Pagelet('feed'))->appendContent('<p>The feed.</p>');
?>
<main><?= $feed ?></main>
<?= \dobron\BigPipe\BigPipe::render() ?>Render slow pagelets with defer() and send them as soon as they are ready with BigPipe::stream(), load them when
they become visible with lazy pagelets, or load the next page into the layout with
page transitions. See Pagelets.
Next steps
- Update the page with the DOMOPS API and open dialogs from PHP.
- Learn how a request becomes changes of the page in How it works.
- See a complete page in the pipelined page example.
- Use BigPipe with Laravel or React.