From 31d0a1a1ee8b9ed68aa23d88d6f9ae2dcc63e751 Mon Sep 17 00:00:00 2001 From: "Fred K. Schott" Date: Thu, 21 May 2020 14:57:12 -0700 Subject: [PATCH] add react fast refresh (#62) --- packages/create-snowpack-app/LICENSE | 27 +++++++ .../app-scripts-preact/snowpack.config.js | 5 +- .../app-scripts-react/babel.config.json | 9 +++ .../app-scripts-react/snowpack.config.js | 2 +- .../packages/plugin-babel/plugin.js | 3 - .../plugin-react-refresh/package.json | 13 ++++ .../packages/plugin-react-refresh/plugin.js | 74 +++++++++++++++++++ .../babel.config.json | 3 + .../app-template-react/babel.config.json | 3 + .../templates/app-template-react/src/App.jsx | 7 +- packages/create-snowpack-app/yarn.lock | 43 +---------- 11 files changed, 138 insertions(+), 51 deletions(-) create mode 100644 packages/create-snowpack-app/packages/app-scripts-react/babel.config.json create mode 100644 packages/create-snowpack-app/packages/plugin-react-refresh/package.json create mode 100644 packages/create-snowpack-app/packages/plugin-react-refresh/plugin.js create mode 100644 packages/create-snowpack-app/templates/app-template-react-typescript/babel.config.json create mode 100644 packages/create-snowpack-app/templates/app-template-react/babel.config.json diff --git a/packages/create-snowpack-app/LICENSE b/packages/create-snowpack-app/LICENSE index 829cbe0f90..6bbb589f1d 100644 --- a/packages/create-snowpack-app/LICENSE +++ b/packages/create-snowpack-app/LICENSE @@ -48,3 +48,30 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ + +This license applies to parts of packages/plugin-react-refresh/plugin.js originating +from the https://github.com/vitejs/vite-plugin-react repository: + +""" +MIT License + +Copyright (c) 2020-present, Yuxi (Evan) You + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" \ No newline at end of file diff --git a/packages/create-snowpack-app/packages/app-scripts-preact/snowpack.config.js b/packages/create-snowpack-app/packages/app-scripts-preact/snowpack.config.js index 161ae15183..2b3eb3a994 100644 --- a/packages/create-snowpack-app/packages/app-scripts-preact/snowpack.config.js +++ b/packages/create-snowpack-app/packages/app-scripts-preact/snowpack.config.js @@ -17,12 +17,9 @@ if (isTS) { module.exports = { scripts, + plugins: ["@snowpack/plugin-babel", "@prefresh/snowpack"], devOptions: {}, installOptions: { installTypes: isTS, }, - plugins: [ - "@snowpack/plugin-babel", - "@prefresh/snowpack" - ] }; diff --git a/packages/create-snowpack-app/packages/app-scripts-react/babel.config.json b/packages/create-snowpack-app/packages/app-scripts-react/babel.config.json new file mode 100644 index 0000000000..cf74e349cf --- /dev/null +++ b/packages/create-snowpack-app/packages/app-scripts-react/babel.config.json @@ -0,0 +1,9 @@ +{ + "presets": [["@babel/preset-react"], "@babel/preset-typescript"], + "plugins": ["@babel/plugin-syntax-import-meta"], + "env": { + "development": { + "plugins": ["react-refresh/babel"] + } + } +} diff --git a/packages/create-snowpack-app/packages/app-scripts-react/snowpack.config.js b/packages/create-snowpack-app/packages/app-scripts-react/snowpack.config.js index 104afef431..80649f5dd0 100644 --- a/packages/create-snowpack-app/packages/app-scripts-react/snowpack.config.js +++ b/packages/create-snowpack-app/packages/app-scripts-react/snowpack.config.js @@ -6,7 +6,6 @@ const isTS = fs.existsSync(path.join(cwd, "tsconfig.json")); const scripts = { "mount:public": "mount public --to /", - "mount:web_modules": "mount web_modules", "mount:src": "mount src --to /_dist_", }; @@ -17,6 +16,7 @@ if (isTS) { module.exports = { scripts, + plugins: ["@snowpack/plugin-babel", "@snowpack/plugin-react-refresh"], devOptions: {}, installOptions: { installTypes: isTS, diff --git a/packages/create-snowpack-app/packages/plugin-babel/plugin.js b/packages/create-snowpack-app/packages/plugin-babel/plugin.js index 76d2e77990..8991012119 100644 --- a/packages/create-snowpack-app/packages/plugin-babel/plugin.js +++ b/packages/create-snowpack-app/packages/plugin-babel/plugin.js @@ -4,9 +4,6 @@ module.exports = function plugin(config, options) { return { defaultBuildScript: "build:js,jsx,ts,tsx", async build({ contents, filePath, fileContents }) { - if (filePath.includes("web_modules")) { - return { result: contents }; - } const result = await babel.transformAsync(contents || fileContents, { filename: filePath, cwd: process.cwd(), diff --git a/packages/create-snowpack-app/packages/plugin-react-refresh/package.json b/packages/create-snowpack-app/packages/plugin-react-refresh/package.json new file mode 100644 index 0000000000..a54d8d350e --- /dev/null +++ b/packages/create-snowpack-app/packages/plugin-react-refresh/package.json @@ -0,0 +1,13 @@ +{ + "name": "@snowpack/plugin-react-refresh", + "version": "0.6.2", + "main": "plugin.js", + "license": "MIT", + "publishConfig": { + "access": "public" + }, + "dependencies": { + "react-refresh": "^0.8.0" + }, + "gitHead": "795f4311d79a70cc9f19f21b512b7f8675d73f17" +} diff --git a/packages/create-snowpack-app/packages/plugin-react-refresh/plugin.js b/packages/create-snowpack-app/packages/plugin-react-refresh/plugin.js new file mode 100644 index 0000000000..2e76d73a83 --- /dev/null +++ b/packages/create-snowpack-app/packages/plugin-react-refresh/plugin.js @@ -0,0 +1,74 @@ +/** + * @snowpack/plugin-react-refresh (Fast Refresh) + * Based on details provided by: + * - https://github.com/facebook/react/issues/16604#issuecomment-528663101 + * - https://github.com/vitejs/vite-plugin-react (see LICENSE) + */ + +const fs = require("fs"); + +const reactRefreshLoc = require.resolve( + "react-refresh/cjs/react-refresh-runtime.development.js" +); +const reactRefreshCode = fs + .readFileSync(reactRefreshLoc, { encoding: "utf-8" }) + .replace(`process.env.NODE_ENV`, JSON.stringify("development")); + +function transformHtml(contents, urlPath) { + return contents.replace( + //, + `$& +` + ); +} + +function transformJs(contents, urlPath) { + return ` +/** React Refresh: Setup **/ +if (import.meta.hot) { + var prevRefreshReg = window.$RefreshReg$; + var prevRefreshSig = window.$RefreshSig$; + window.$RefreshReg$ = (type, id) => { + window.$RefreshRuntime$.register(type, ${JSON.stringify( + urlPath + )} + " " + id); + } + window.$RefreshSig$ = window.$RefreshRuntime$.createSignatureFunctionForTransform; +} + +${contents} + +/** React Refresh: Connect **/ +if (import.meta.hot) { + window.$RefreshReg$ = prevRefreshReg + window.$RefreshSig$ = prevRefreshSig + import.meta.hot.accept(() => { + window.$RefreshRuntime$.performReactRefresh() + }); +}`; +} + +module.exports = function reactRefreshTransform() { + return { + transform({ contents, urlPath, isDev }) { + if (!isDev) { + return null; + } + if (urlPath.endsWith(".js") && /\$RefreshReg\$\(/.test(contents)) { + return { result: transformJs(contents, urlPath) }; + } + if (urlPath.endsWith("/") || urlPath.endsWith(".html")) { + return { result: transformHtml(contents, urlPath) }; + } + }, + }; +}; diff --git a/packages/create-snowpack-app/templates/app-template-react-typescript/babel.config.json b/packages/create-snowpack-app/templates/app-template-react-typescript/babel.config.json new file mode 100644 index 0000000000..9357351e1a --- /dev/null +++ b/packages/create-snowpack-app/templates/app-template-react-typescript/babel.config.json @@ -0,0 +1,3 @@ +{ + "extends": "@snowpack/app-scripts-react/babel.config.json" +} diff --git a/packages/create-snowpack-app/templates/app-template-react/babel.config.json b/packages/create-snowpack-app/templates/app-template-react/babel.config.json new file mode 100644 index 0000000000..9357351e1a --- /dev/null +++ b/packages/create-snowpack-app/templates/app-template-react/babel.config.json @@ -0,0 +1,3 @@ +{ + "extends": "@snowpack/app-scripts-react/babel.config.json" +} diff --git a/packages/create-snowpack-app/templates/app-template-react/src/App.jsx b/packages/create-snowpack-app/templates/app-template-react/src/App.jsx index c5636a00e6..d2b0d5c2d4 100644 --- a/packages/create-snowpack-app/templates/app-template-react/src/App.jsx +++ b/packages/create-snowpack-app/templates/app-template-react/src/App.jsx @@ -1,14 +1,17 @@ -import React from 'react'; +import React, { useState } from 'react'; import logo from './logo.svg'; import './App.css'; function App() { + // TODO: Remove before merging, this was just for fast-refresh testing + const [counter, setCounter] = useState(5); + setTimeout(() => setCounter(counter + 1), 1000); return (
logo

- Edit src/App.jsx and save to reload. + {counter} Edit src/App.jsx and save to reload.