Skip to content

Commit

Permalink
Switch to Snowpack's dev task for speed and HMR
Browse files Browse the repository at this point in the history
See #3 - This fixes HMR, but not React Fast Refresh
  • Loading branch information
iandunn committed Feb 12, 2021
1 parent fca829a commit 6ac10fa
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 27 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"__scripts:comment:bundle2": "todo: could improve it by deleting everything except _snowpack - something like rm -rfvi !('build/_snowpack'). be careful not to delete anything above build/",
"scripts": {
"bundle": "npm run build && rm -f build/index.js",
"watch": "snowpack build --watch --hmr",
"watch": "snowpack dev",
"build": "snowpack build"
}
}
42 changes: 29 additions & 13 deletions plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,22 @@ function get_serve_folder() {
return $folder;
}

// Note: This is only necessary to demonstrate different approaches. In real-world applications you'd either
// commit to running the watch task or not, or at least the application code wouldn't care which.
function running_watch_task() {
static $running = null; // Cache the result so it's not run more than once per page load.

if ( null === $running ) {
$null = null;
$running = is_resource( @fsockopen( 'localhost', '8081', $null, $null, 1 ) );

if ( ! $running ) {
error_clear_last(); // Prevent the `body.php-error` CSS class from being added.
}
}

return $running;
}

// register/enqueue scripts & styles
add_action( 'admin_enqueue_scripts', function( $hook_suffix ) {
Expand All @@ -95,6 +111,13 @@ function get_serve_folder() {
// need to add wp-polyfill as a dependency? maybe for api-fetch & other stuff
// it's added automatically?
if ( running_watch_task() ) {
$script_url = 'http://localhost:8081/index.js';
// make url/port DRY w/ websocket below
} else {
$script_url = plugins_url( "$folder/index.js", __FILE__ );
}

if ( 'source' === $folder ) {
// Don't need HTM in production, because Babel transpiles it away.
$dependencies[] = 'htm';
Expand All @@ -106,7 +129,8 @@ function get_serve_folder() {

wp_enqueue_script(
'no-build-tools-no-problems',
plugins_url( "$folder/index.js", __FILE__ ),
$script_url,
/// rename to more specific
$dependencies,
filemtime( __DIR__ . "/$folder/index.js" ),

Expand Down Expand Up @@ -164,27 +188,19 @@ function get_serve_folder() {
<?php
} );

// setup auto reloading
// actual hmr isn't working yet -- https://github.com/snowpackjs/snowpack/discussions/2565
// configure hot module reloading
// should be in core.php?
add_action( 'admin_print_scripts-toplevel_page_no-build-tools-no-problems', function() {
$hmr_folder = '/build/vendor/';

if ( ! file_exists( __DIR__ . $hmr_folder . '/hmr-client.js' ) ) {
// return early if not running watch task, how to detect?
// presence of hmr-client in vendor folder? no b/c bundle task doesn't delete it
if ( ! running_watch_task() ) {
return;
}

?>

<script>
// is it safe to hardcode that port? maybe set it in config file and pull from .env file?
window.HMR_WEBSOCKET_URL = 'ws://localhost:12321';
// not safe to hardcode the port. maybe set it in config file and pull from .env file?
window.HMR_WEBSOCKET_URL = 'ws://localhost:8081';
</script>

<script type="module" src="<?php echo plugins_url( $hmr_folder . '/hmr-client.js', __FILE__ ); ?>"></script>
<script type="module" src="<?php echo plugins_url( $hmr_folder . '/hmr-error-overlay.js', __FILE__ ); ?>"></script>

<?php
} );
8 changes: 4 additions & 4 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ You can run the same `source/` scripts in production if you'd like. For smaller

If that's where you're at, you can `rm .gitignore babel.config.js package.json package-lock.json`, and revel in how tidy your root folder is.

If want to optimize performance, or need to support older browsers, then you can add a build step for production files. You'll still be able to develop locally without any `watch` tooling, though.
If want to optimize performance, or need to support older browsers, then you can use the <code>build</code> step for your production files. You'll still be able to develop locally without any `watch` tooling, though.

1. `npm install`
1. `npm run build`
Expand All @@ -42,15 +42,15 @@ There are two ways to import dependencies, depending on your needs and preferenc

1. **Locally bundled packages:** You can also bundle packages locally if you prefer, but still much faster and more conveniently than traditional approaches.

[Snowpack](https://snowpack.dev) is used to generate bundles 10x faster than Webpack, and only when needed. You don't need to run a `watch` task, just `npm run bundle` when you add/remove a dependency. It still does tree-shaking, will automatically up-convert CommonJS modules to ESM, and has a much more ergonomic approach to package locking.
[Snowpack](https://snowpack.dev) is used to generate bundles 10x faster than Webpack, and only when needed. You don't need to run the `watch` task, just `npm run bundle` when you add/remove a dependency. It still does tree-shaking, will automatically up-convert CommonJS modules to ESM, and has a much more ergonomic approach to package locking.


### Optional Tooling for Improved Developer Experience

<code>npm run watch</code> will add additional features, but it's not required.

* Today: Live reloading and PostCSS.
* Future: Hot Module Reloading, React Fast Refresh.
* Today: Hot Module Reloading and PostCSS.
* Future: React Fast Refresh.


### Results
Expand Down
6 changes: 4 additions & 2 deletions snowpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,10 @@ module.exports = {
source: 'remote',
},

// Not using their localhost server because need everything to run inside WordPress/PHP context.
//devOptions: {},
devOptions: {
port: 8081, // Avoid conflicts with proxies on 8080.
open: 'none', // Devs will still visit the WP/PHP server URL in their browser.
},

buildOptions: {
metaUrlPath : 'vendor',
Expand Down
2 changes: 1 addition & 1 deletion source/baseline/latest-posts.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export class LatestPostsCard extends Component {

render = () => {
const { loaded, loading, posts } = this.state;
const componentUrl = getBaseUrl() + '/baseline/';
const componentUrl = getBaseUrl() + '/baseline';

return html`
<${Fragment}>
Expand Down
21 changes: 17 additions & 4 deletions source/developer-experience/developer-experience.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import { getLoadPath, getBaseUrl } from '../utilities.js';

export function DeveloperExperience() {
const loadPath = getLoadPath();
const componentUrl = getBaseUrl() + '/developer-experience/';
const watching = 'object' === typeof import.meta?.hot;
const componentUrl = getBaseUrl() + '/developer-experience';

return html`
<${Fragment}>
Expand Down Expand Up @@ -43,11 +44,23 @@ export function DeveloperExperience() {
</p>
</div>
${ 'source' === loadPath && html`
${ 'source' === loadPath && ! watching && html`
<${ Notice } status="info" isDismissible=${ false } >
<p>
You're running from <code>source/</code>, so the nested styles won't apply, and the image below will be blurred.
<code>npm run build</code> and refresh to load the <code>build/</code> files, where PostCSS will transform the nested styles to vanilla CSS and un-blur the image.
You're running from <code>source/</code> without the <code>watch</code> task, so the nested styles won't apply, and the image below will be blurred.
<code>npm run watch</code> or <code>npm run build</code> and then refresh. That will cause PostCSS to transform the nested styles to vanilla CSS, and un-blur the image.
</p>
<//>
` }
${ watching && html`
<${ Notice } status="info" isDismissible=${ false } >
<p>
You're running the <code>watch</code> task, so the nested styles <em>will</em> apply, and the image below will <strong>not</strong> be blurred.
<code>Control-C</code> in your terminal to cancel the watch task, then refresh to load the unprocessed files. When you do, the image will be blurred.
</p>
<//>
` }
Expand Down
4 changes: 4 additions & 0 deletions source/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ const html = wp.html;
const { Fragment } = wp.element;
const { renderLoadingContainer } = wp.utils;

// This is required for HMR to work, because we're using WP to serve the HTML instead of Snowpack's localhost server.
if ( import.meta.hot ) {
import.meta.hot.accept();
}

/**
* Internal dependencies
Expand Down
3 changes: 2 additions & 1 deletion source/local-bundling/passphrase-generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const html = wp.html;
*/
//import { v4 as uuidv4 } from 'uuid'; // Native ESM
//import { argon2id } from 'hash-wasm'; // Native ESM
// maybe change these to dynamic imports, so could flip the card on/off automatically based on import.meta.hot || build === path?

// todo convert these to import maps too, but need to wait until https://github.com/snowpackjs/snowpack/discussions/2548 is released
// then check if can destructure specific functions from any of these, since snowpack will be is bundling
Expand Down Expand Up @@ -140,7 +141,7 @@ export class PassphraseGenerator extends Component {
const dependenciesAvailable = 'function' === typeof uuidv4 && 'function' === typeof argon2id;
// todo add others when they're loaded from local bundle

const componentUrl = getBaseUrl() + '/local-bundling/';
const componentUrl = getBaseUrl() + '/local-bundling';

return html`
<${Fragment}>
Expand Down
2 changes: 1 addition & 1 deletion source/utilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
export function getBaseUrl() {
const scriptUrl = document.getElementById( 'no-build-tools-no-problems-js' ).getAttribute( 'src' );

return scriptUrl.substring( 0, scriptUrl.lastIndexOf( '/' ) ) + '/';
return scriptUrl.substring( 0, scriptUrl.lastIndexOf( '/' ) );
}

// Returns 'build' if loaded from `build/` folder, 'source' otherwise
Expand Down

0 comments on commit 6ac10fa

Please sign in to comment.