diff --git a/loaders/ignore-import.js b/loaders/ignore-import.js new file mode 100644 index 00000000..27ca5da3 --- /dev/null +++ b/loaders/ignore-import.js @@ -0,0 +1,10 @@ +'use strict'; +/* +Copyright (c) 2016 Cherry Ng +MIT Licensed +https://npmjs.com/package/ignore-loader +*/ +module.exports = function() { + this.cacheable && this.cacheable(); + return ''; +} \ No newline at end of file diff --git a/loaders/string-replace.js b/loaders/string-replace.js new file mode 100644 index 00000000..5b66199b --- /dev/null +++ b/loaders/string-replace.js @@ -0,0 +1,20 @@ +/* +Copyright (c) 2015 Valentyn Barmashyn +MIT Licensed +Original: https://npmjs.com/package/ignore-loader +*/ +module.exports = function(source, map) { + this.cacheable(); + + const optionsArray = this.getOptions().multiple; + let newSource = source; + + for (const options of optionsArray) { + newSource = newSource.replace( + new RegExp(options.search, options.search.flags || options.flags || ''), + options.replace + ); + } + + this.callback(null, newSource, map); +} \ No newline at end of file diff --git a/package.json b/package.json index 4d4dcbbc..00b41d5e 100644 --- a/package.json +++ b/package.json @@ -12,18 +12,9 @@ }, "types": "./types/index.d.ts", "dependencies": { - "@babel/cli": "^7.0.0", - "@babel/core": "^7.2.2", - "@babel/node": "^7.2.2", - "@babel/plugin-proposal-class-properties": "^7.2.3", - "@babel/plugin-proposal-decorators": "^7.2.3", - "@babel/plugin-proposal-export-default-from": "^7.2.0", - "@babel/plugin-transform-react-jsx": "^7.8.3", - "@babel/plugin-transform-typescript": "^7.16.1", - "@babel/preset-env": "^7.2.3", - "@babel/preset-react": "^7.0.0", - "babel-loader": "^8.0.5", - "babel-plugin-transform-decorators-legacy": "^1.3.5", + "@swc/core": "^1.2.171", + "@babel/parser": "^7.2.2", + "@babel/traverse": "^7.2.2", "body-parser": "^1.19.0", "commander": "^8.3.0", "cors": "^2.8.5", @@ -31,20 +22,14 @@ "dotenv": "^8.2.0", "express": "^4.17.1", "fs-extra": "^10.0.0", - "ignore-loader": "^0.1.2", "mini-css-extract-plugin": "^2.4.5", "node-fetch": "2.6.7", "nodemon-webpack-plugin": "^4.3.1", - "raw-loader": "^4.0.2", "sass": "^1.32.11", "sass-loader": "^8.0.2", - "string-replace-loader": "^3.1.0", + "swc-loader": "^0.2.0", "terser-webpack-plugin": "^5.3.0", - "ts-loader": "^9.2.6", - "typescript": "^4.5.3", "webpack": "^5.65.0", - "webpack-cli": "^4.9.1", - "webpack-livereload-plugin": "^2.3.0", "ws": "^7.4.4" } } \ No newline at end of file diff --git a/server/worker.js b/server/worker.js index 26e41845..f6aa7834 100644 --- a/server/worker.js +++ b/server/worker.js @@ -1,14 +1,14 @@ -import activate from '!!raw-loader!../workers/activate.js'; -import cacheFirst from '!!raw-loader!../workers/cacheFirst.js'; -import dynamicFetch from '!!raw-loader!../workers/dynamicFetch.js'; -import dynamicInstall from '!!raw-loader!../workers/dynamicInstall.js'; -import load from '!!raw-loader!../workers/load.js'; -import networkDataFirst from '!!raw-loader!../workers/networkDataFirst.js'; -import networkFirst from '!!raw-loader!../workers/networkFirst.js'; -import staleWhileRevalidate from '!!raw-loader!../workers/staleWhileRevalidate.js'; -import staticFetch from '!!raw-loader!../workers/staticFetch.js'; -import staticHelpers from '!!raw-loader!../workers/staticHelpers.js'; -import staticInstall from '!!raw-loader!../workers/staticInstall.js'; +import activate from '../workers/activate.js?raw'; +import cacheFirst from '../workers/cacheFirst.js?raw'; +import dynamicFetch from '../workers/dynamicFetch.js?raw'; +import dynamicInstall from '../workers/dynamicInstall.js?raw'; +import load from '../workers/load.js?raw'; +import networkDataFirst from '../workers/networkDataFirst.js?raw'; +import networkFirst from '../workers/networkFirst.js?raw'; +import staleWhileRevalidate from '../workers/staleWhileRevalidate.js?raw'; +import staticFetch from '../workers/staticFetch.js?raw'; +import staticHelpers from '../workers/staticHelpers.js?raw'; +import staticInstall from '../workers/staticInstall.js?raw'; import { existsSync, readdirSync, readFileSync } from 'fs'; import path from 'path'; import environment from './environment'; diff --git a/tests/package.json b/tests/package.json index 94902f6d..25239476 100644 --- a/tests/package.json +++ b/tests/package.json @@ -9,7 +9,6 @@ "nullstack": "*", "puppeteer": "^5.5.0", "jest-puppeteer": "^6.0.3", - "webpack-cli": "^3.3.12", "glob": "^7.1.7", "purgecss-webpack-plugin": "^4.1.3" }, diff --git a/webpack.config.js b/webpack.config.js index 8503c7f0..2b65e0fd 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -7,6 +7,11 @@ const { readdirSync } = require('fs'); const buildKey = crypto.randomBytes(20).toString('hex'); +function getLoader(loader) { + const loaders = path.resolve('./node_modules/nullstack/loaders'); + return path.join(loaders, loader); +} + function cacheFactory(args, folder, name) { if (args.cache || args.environment === 'development') { return { @@ -19,70 +24,79 @@ function cacheFactory(args, folder, name) { } } -const babel = { +function terserMinimizer(file, _sourceMap) { + return require('@swc/core').minify(file, { + keepClassnames: true, + keepFnames: true + }) +} + +const swc = { test: /\.js$/, - resolve: { - extensions: ['.njs', '.js', '.nts', '.ts', '.tsx', '.jsx'] - }, use: { - loader: require.resolve('babel-loader'), + loader: require.resolve('swc-loader'), options: { - "presets": [ - ["@babel/preset-env", { "targets": { node: "10" } }] - ], - "plugins": [ - "@babel/plugin-proposal-export-default-from", - "@babel/plugin-proposal-class-properties" - ] + jsc: { + parser: { + syntax: "ecmascript", + exportDefaultFrom: true + } + }, + env: { + targets: { node: "10" } + } } } }; const nullstackJavascript = { test: /\.(njs|nts|jsx|tsx)$/, - resolve: { - extensions: ['.njs', '.js', '.nts', '.ts', '.tsx', '.jsx'] - }, use: { - loader: require.resolve('babel-loader'), + loader: require.resolve('swc-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 - }] - ] + jsc: { + parser: { + syntax: "ecmascript", + exportDefaultFrom: true, + jsx: true + }, + transform: { + react: { + pragma: "Nullstack.element", + pragmaFrag: "Nullstack.fragment", + throwIfNamespace: true + } + } + }, + env: { + targets: { node: "10" } + } } } }; const nullstackTypescript = { test: /\.(nts|tsx)$/, - resolve: { - extensions: ['.njs', '.js', '.nts', '.ts', '.tsx', '.jsx'] - }, use: { - loader: require.resolve('babel-loader'), + loader: require.resolve('swc-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-transform-react-jsx", { - "pragma": "Nullstack.element", - "pragmaFrag": "Nullstack.fragment", - "throwIfNamespace": false - }] - ] + jsc: { + parser: { + syntax: "typescript", + exportDefaultFrom: true, + tsx: true + }, + transform: { + react: { + pragma: "Nullstack.element", + pragmaFrag: "Nullstack.fragment", + throwIfNamespace: true + } + } + }, + env: { + targets: { node: "10" } + } } } }; @@ -97,10 +111,11 @@ function server(env, argv) { icons[size] = '/' + file; } } - const folder = argv.environment === 'development' ? '.development' : '.production'; - const devtool = argv.environment === 'development' ? 'inline-cheap-module-source-map' : false; - const minimize = argv.environment !== 'development'; - const plugins = argv.environment === 'development' ? ([ + const isDev = argv.environment === 'development'; + const folder = isDev ? '.development' : '.production'; + const devtool = isDev ? 'inline-cheap-module-source-map' : false; + const minimize = !isDev; + const plugins = isDev ? ([ new NodemonPlugin({ watch: path.resolve('./.development'), script: './.development/server.js', @@ -116,14 +131,14 @@ function server(env, argv) { filename: 'server.js', libraryTarget: 'umd' }, + resolve: { + extensions: ['.njs', '.js', '.nts', '.ts', '.tsx', '.jsx'] + }, optimization: { minimize: minimize, minimizer: [ new TerserPlugin({ - terserOptions: { - //keep_classnames: true, - keep_fnames: true - }, + minify: terserMinimizer, // workaround: disable parallel to allow caching server parallel: argv.cache ? false : require('os').cpus().length - 1 }) @@ -135,56 +150,70 @@ function server(env, argv) { rules: [ { test: /nullstack.js$/, - loader: require.resolve('string-replace-loader'), + loader: getLoader('string-replace.js'), options: { multiple: [ - { search: '{{NULLSTACK_ENVIRONMENT_NAME}}', replace: 'server', flags: 'ig' } + { + search: /{{NULLSTACK_ENVIRONMENT_NAME}}/ig, + replace: 'server' + } ] } }, { test: /environment.js$/, - loader: require.resolve('string-replace-loader'), + loader: getLoader('string-replace.js'), options: { multiple: [ - { search: '{{NULLSTACK_ENVIRONMENT_KEY}}', replace: buildKey, flags: 'ig' } + { + search: /{{NULLSTACK_ENVIRONMENT_KEY}}/ig, + replace: buildKey + } ] } }, { test: /project.js$/, - loader: require.resolve('string-replace-loader'), + loader: getLoader('string-replace.js'), options: { multiple: [ - { search: '{{NULLSTACK_PROJECT_ICONS}}', replace: JSON.stringify(icons), flags: 'ig' } + { + search: /{{NULLSTACK_PROJECT_ICONS}}/ig, + replace: JSON.stringify(icons) + } ] } }, - babel, + swc, nullstackJavascript, { test: /\.(njs|nts|jsx|tsx)$/, - loader: path.resolve('./node_modules/nullstack/loaders/inject-nullstack.js'), + loader: getLoader('inject-nullstack.js'), }, { test: /\.(njs|nts|jsx|tsx)$/, - loader: path.resolve('./node_modules/nullstack/loaders/register-static-from-server.js'), + loader: getLoader('register-static-from-server.js'), }, { test: /\.s?[ac]ss$/, use: [ - { loader: require.resolve('ignore-loader') } + { loader: getLoader('ignore-import.js') } ] }, nullstackTypescript, { test: /\.(njs|nts|jsx|tsx)$/, - loader: path.resolve('./node_modules/nullstack/loaders/add-source-to-node.js'), + loader: getLoader('add-source-to-node.js'), }, { test: /\.(njs|nts|jsx|tsx)$/, - loader: path.resolve('./node_modules/nullstack/loaders/register-inner-components.js'), + loader: getLoader('register-inner-components.js'), }, + { + issuer: /worker.js/, + resourceQuery: /raw/, + type: 'asset/source', + } ] }, target: 'node', @@ -199,15 +228,16 @@ function server(env, argv) { function client(env, argv) { const dir = argv.input ? path.join(__dirname, argv.input) : process.cwd(); - const folder = argv.environment === 'development' ? '.development' : '.production'; - const devtool = argv.environment === 'development' ? 'inline-cheap-module-source-map' : false; - const minimize = argv.environment !== 'development'; + const isDev = argv.environment === 'development'; + const folder = isDev ? '.development' : '.production'; + const devtool = isDev ? 'inline-cheap-module-source-map' : false; + const minimize = !isDev; let liveReload = {}; - if (argv.environment !== 'development') { + if (!isDev) { liveReload = { test: /liveReload.js$/, use: [ - { loader: require.resolve('ignore-loader') } + { loader: getLoader('ignore-import.js') } ] } } @@ -224,14 +254,14 @@ function client(env, argv) { path: path.join(dir, folder), filename: 'client.js' }, + resolve: { + extensions: ['.njs', '.js', '.nts', '.ts', '.tsx', '.jsx'] + }, optimization: { minimize: minimize, minimizer: [ new TerserPlugin({ - terserOptions: { - //keep_classnames: true, - keep_fnames: true - } + minify: terserMinimizer }) ] }, @@ -241,26 +271,29 @@ function client(env, argv) { rules: [ { test: /nullstack.js$/, - loader: require.resolve('string-replace-loader'), + loader: getLoader('string-replace.js'), options: { multiple: [ - { search: '{{NULLSTACK_ENVIRONMENT_NAME}}', replace: 'client', flags: 'ig' } + { + search: /{{NULLSTACK_ENVIRONMENT_NAME}}/ig, + replace: 'client' + } ] } }, - babel, + swc, nullstackJavascript, { test: /\.(njs|nts|jsx|tsx)$/, - loader: path.resolve('./node_modules/nullstack/loaders/remove-import-from-client.js'), + loader: getLoader('remove-import-from-client.js'), }, { test: /\.(njs|nts|jsx|tsx)$/, - loader: path.resolve('./node_modules/nullstack/loaders/inject-nullstack.js'), + loader: getLoader('inject-nullstack.js'), }, { test: /\.(njs|nts|jsx|tsx)$/, - loader: path.resolve('./node_modules/nullstack/loaders/remove-static-from-client.js'), + loader: getLoader('remove-static-from-client.js'), }, { test: /\.s?[ac]ss$/, @@ -274,11 +307,11 @@ function client(env, argv) { nullstackTypescript, { test: /\.(njs|nts|jsx|tsx)$/, - loader: path.resolve('./node_modules/nullstack/loaders/add-source-to-node.js'), + loader: getLoader('add-source-to-node.js'), }, { test: /\.(njs|nts|jsx|tsx)$/, - loader: path.resolve('./node_modules/nullstack/loaders/register-inner-components.js'), + loader: getLoader('register-inner-components.js'), }, ] },