diff --git a/client/index.js b/client/index.js index 887bd72c..a0a77067 100644 --- a/client/index.js +++ b/client/index.js @@ -109,17 +109,17 @@ export default class Nullstack { if (module.hot) { const socket = new WebSocket('ws' + router.base.slice(4) + '/ws'); - window.lastHash + Nullstack.lastHash socket.onmessage = async function (e) { const data = JSON.parse(e.data) if (data.type === 'NULLSTACK_SERVER_STARTED') { - (window.needsReload || !environment.hot) && window.location.reload() + (Nullstack.needsReload || !environment.hot) && window.location.reload() } else if (data.type === 'hash') { const newHash = data.data.slice(20) - if (newHash === window.lastHash) { - window.needsReload = true + if (newHash === Nullstack.lastHash) { + Nullstack.needsReload = true } else { - window.lastHash = newHash + Nullstack.lastHash = newHash } } }; diff --git a/loaders/inject-hmr.js b/loaders/inject-hmr.js index 8d325d03..28fb5af8 100644 --- a/loaders/inject-hmr.js +++ b/loaders/inject-hmr.js @@ -26,11 +26,11 @@ module.exports = function (source) { return source + ` if (module.hot) { - if (window.needsClientReload) { + if (Nullstack.needsClientReload) { window.location.reload() } module.hot.accept() - window.needsClientReload = true + Nullstack.needsClientReload = true module.hot.accept('${klassPath}', () => { Nullstack.hotReload(${klassName}) }) diff --git a/package.json b/package.json index a3eae620..437bff83 100644 --- a/package.json +++ b/package.json @@ -12,9 +12,17 @@ }, "types": "./types/index.d.ts", "dependencies": { + "@babel/core": "^7.18.13", "@babel/parser": "7.17.12", + "@babel/preset-env": "^7.18.10", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-export-default-from": "^7.18.10", + "@babel/plugin-transform-react-jsx": "^7.18.10", + "@babel/plugin-transform-typescript": "^7.18.12", + "@babel/preset-react": "^7.18.6", "@babel/traverse": "7.17.12", "@swc/core": "1.2.179", + "babel-loader": "^8.2.5", "body-parser": "1.20.0", "commander": "8.3.0", "copy-webpack-plugin": "^11.0.0", diff --git a/scripts/index.js b/scripts/index.js index 34034d1f..e699ca24 100755 --- a/scripts/index.js +++ b/scripts/index.js @@ -4,7 +4,7 @@ const { version } = require('../package.json'); const webpack = require('webpack'); const path = require('path'); -const { existsSync, rmdirSync, readdir, unlink } = require('fs'); +const { existsSync, readdir, unlink } = require('fs'); const customConfig = path.resolve(process.cwd(), './webpack.config.js'); const config = existsSync(customConfig) ? require(customConfig) : require('../webpack.config'); const dotenv = require('dotenv') @@ -61,7 +61,7 @@ function clearOutput(outputPath) { }); } -async function start({ input, port, env, mode = 'spa', cold, disk }) { +async function start({ input, port, env, mode = 'spa', cold, disk, loader = 'swc' }) { const environment = 'development' console.log(` 🚀️ Starting your application in ${environment} mode...`); loadEnv(env) @@ -85,7 +85,7 @@ async function start({ input, port, env, mode = 'spa', cold, disk }) { host: process.env['NULLSTACK_PROJECT_DOMAIN'], devMiddleware: { index: false, - stats: 'none', + stats: 'errors-only', writeToDisk, }, client: { @@ -135,7 +135,7 @@ async function start({ input, port, env, mode = 'spa', cold, disk }) { webSocketServer: require.resolve('./socket'), port: process.env['NULLSTACK_SERVER_PORT'] }; - const compiler = getCompiler({ environment, input, disk }); + const compiler = getCompiler({ environment, input, disk, loader }); clearOutput(compiler.compilers[0].outputPath) const server = new WebpackDevServer(devServerOptions, compiler); const portChecker = require('express')().listen(process.env['NULLSTACK_SERVER_PORT'], () => { @@ -173,6 +173,7 @@ program .option('-e, --env ', 'Name of the environment file that should be loaded') .option('-d, --disk', 'Write files to disk') .option('-c, --cold', 'Disable hot module replacement') + .addOption(new program.Option('-l, --loader ', 'Use Babel or SWC loader').choices(['swc', 'babel'])) .helpOption('-h, --help', 'Learn more about this command') .action(start) diff --git a/webpack.config.js b/webpack.config.js index 6349cd61..347516d4 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -56,6 +56,25 @@ const swcJs = { } }; +const babelJs = { + test: /\.js$/, + resolve: { + extensions: ['.njs', '.js', '.nts', '.ts', '.jsx', '.tsx'] + }, + use: { + loader: require.resolve('babel-loader'), + options: { + "presets": [ + ["@babel/preset-env", { "targets": { node: "10" } }] + ], + "plugins": [ + "@babel/plugin-proposal-export-default-from", + "@babel/plugin-proposal-class-properties" + ] + } + } +}; + const swcTs = { test: /\.ts$/, use: { @@ -74,7 +93,28 @@ const swcTs = { } }; -const nullstackJavascript = { +const babelTs = { + test: /\.ts$/, + resolve: { + extensions: ['.njs', '.js', '.nts', '.ts', '.jsx', '.tsx'] + }, + use: { + loader: require.resolve('babel-loader'), + options: { + "presets": [ + ["@babel/preset-env", { "targets": { node: "10" } }], + "@babel/preset-react", + ], + "plugins": [ + "@babel/plugin-transform-typescript", + // "@babel/plugin-proposal-export-default-from", + // "@babel/plugin-proposal-class-properties" + ] + } + } +}; + +const swcNullstackJavascript = { test: /\.(njs|nts|jsx|tsx)$/, use: { loader: require.resolve('swc-loader'), @@ -100,7 +140,32 @@ const nullstackJavascript = { } }; -const nullstackTypescript = { +const babelNullstackJavascript = { + test: /\.(njs|jsx)$/, + resolve: { + extensions: ['.njs', '.js', '.nts', '.ts', '.jsx', '.tsx'] + }, + use: { + loader: require.resolve('babel-loader'), + options: { + "presets": [ + ["@babel/preset-env", { "targets": { node: "10" } }], + "@babel/preset-react", + ], + "plugins": [ + "@babel/plugin-proposal-export-default-from", + "@babel/plugin-proposal-class-properties", + ["@babel/plugin-transform-react-jsx", { + "pragma": "Nullstack.element", + "pragmaFrag": "Nullstack.fragment", + "throwIfNamespace": false + }] + ] + } + } +}; + +const swcNullstackTypescript = { test: /\.(nts|tsx)$/, use: { loader: require.resolve('swc-loader'), @@ -126,11 +191,43 @@ const nullstackTypescript = { } }; +const babelNullstackTypescript = { + test: /\.(nts|tsx)$/, + resolve: { + extensions: ['.njs', '.js', '.nts', '.ts', '.jsx', '.tsx'] + }, + use: { + loader: require.resolve('babel-loader'), + options: { + "presets": [ + ["@babel/preset-env", { "targets": { node: "10" } }], + "@babel/preset-react", + ], + "plugins": [ + ["@babel/plugin-transform-typescript", { + isTSX: true, + allExtensions: true, + tsxPragma: "Nullstack.element", + tsxPragmaFrag: "Nullstack.fragment" + }], + // "@babel/plugin-proposal-export-default-from", + // "@babel/plugin-proposal-class-properties", + ["@babel/plugin-transform-react-jsx", { + "pragma": "Nullstack.element", + "pragmaFrag": "Nullstack.fragment", + "throwIfNamespace": false + }] + ] + } + } +}; + function server(env, argv) { const dir = argv.input ? path.join(__dirname, argv.input) : process.cwd(); const entryExtension = existsSync(path.join(dir, 'server.ts')) ? 'ts' : 'js'; const icons = {}; const publicFiles = readdirSync(path.join(dir, 'public')); + const babel = argv.babel; for (const file of publicFiles) { if (file.startsWith('icon-')) { const size = file.split('x')[1].split('.')[0]; @@ -216,9 +313,9 @@ function server(env, argv) { ] } }, - swcJs, - swcTs, - nullstackJavascript, + babel ? babelJs : swcJs, + babel ? babelTs : swcTs, + babel ? babelNullstackJavascript : swcNullstackJavascript, { test: /\.(njs|nts|jsx|tsx)$/, loader: getLoader('inject-nullstack.js'), @@ -237,7 +334,7 @@ function server(env, argv) { test: /\.(njs|nts|jsx|tsx)$/, loader: getLoader('register-inner-components.js'), }, - nullstackTypescript, + babel ? babelNullstackTypescript : swcNullstackTypescript, { test: /\.(njs|nts|jsx|tsx)$/, loader: getLoader('add-source-to-node.js'), @@ -271,6 +368,7 @@ function client(env, argv) { const folder = isDev ? '.development' : '.production'; const devtool = isDev ? 'inline-cheap-module-source-map' : false; const minimize = !isDev; + const babel = argv.loader === 'babel'; const plugins = [ new MiniCssExtractPlugin({ filename: "client.css", @@ -327,9 +425,9 @@ function client(env, argv) { ] } }, - swcJs, - swcTs, - nullstackJavascript, + babel ? babelJs : swcJs, + babel ? babelTs : swcTs, + babel ? babelNullstackJavascript : swcNullstackJavascript, { test: /\.(njs|nts|jsx|tsx)$/, loader: getLoader('remove-import-from-client.js'), @@ -354,7 +452,7 @@ function client(env, argv) { test: /\.(njs|nts|jsx|tsx)$/, loader: getLoader('register-inner-components.js'), }, - nullstackTypescript, + babel ? babelNullstackTypescript : swcNullstackTypescript, { test: /\.(njs|nts|jsx|tsx)$/, loader: getLoader('add-source-to-node.js'),