diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 60c3fad59..8fd2f8fc4 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [12.x, 14.x, 16.x] + node-version: [18.x, 20.x] steps: - uses: actions/checkout@v2 diff --git a/.mise.toml b/.mise.toml new file mode 100644 index 000000000..efb7c9f99 --- /dev/null +++ b/.mise.toml @@ -0,0 +1,9 @@ +[tools] +node = '20.10.0' +# stuck on this version of yarn because of some weird problems +# related to babel tooling when installing new dependencies +yarn = '1.19.0' + +[env] +MISE_FETCH_REMOTE_VERSIONS_TIMEOUT="300 s" +NODE_OPTIONS = "--openssl-legacy-provider" diff --git a/.nvmrc b/.nvmrc deleted file mode 100644 index 53d838af2..000000000 --- a/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -lts/gallium diff --git a/.yarnrc b/.yarnrc new file mode 100644 index 000000000..a66030138 --- /dev/null +++ b/.yarnrc @@ -0,0 +1 @@ +unsafe-disable-integrity-migration false diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4a03cd0e5..131943816 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -18,13 +18,21 @@ Please make sure all PRs are: If you want to propose a large feature idea or architecture change you should consider submitting an RFC. It's often helpful to get feedback on your concept in an issue before starting the RFC. RFCs are an evolving process in the `kyt` repository so expect a lot of changes and guidelines in the future. You can find the `kyt` RFC template [here](/rfc/template.md). -## kyt local development +## kyt local development workflow -1. `nvm use` 1. Fork and clone `kyt` +1. [setup [mise](https://mise.jdx.dev/) and `mise install`] 1. Run `yarn bootstrap` to install the packages in the monorepo +1. Open a new shell and run `yarn watch` -[lerna](https://github.com/lerna/lerna) is used to manage the monorepo but most of the development commands should be exercised through root directory `package.json` scripts. The following are some useful npm scripts for development: +Most changes are best to develop against the universal starter kyt: + +1. `cd packages/kyt-starter-universal/starter-src` +1. Run `yarn dev` or `yarn build` to test against kyt development and production builds + +Note: After you make changes, the watcher will update libraries but you will likely have to restart the universal app process to test changes. The watcher only works against kyt-core, server and runtime. Changes to babel presets and a few other packages may require you to re-`yarn bootstrap` or `yarn clean-bootstrap`. When in doubt run `yarn clean-bootstrap`. + +[lerna](https://github.com/lerna/lerna) is used to manage the monorepo but most of the development commands should be exercised through root directory `package.json` scripts. ### bootstrap @@ -77,14 +85,12 @@ pushing directly to `main`. For more information on using `lerna` to publish, see [the `lerna publish` documentation](https://github.com/lerna/lerna/tree/main/commands/publish#readme). -### Development Versions +### Publishing Alpha Versions -If you would like your prerelease to have the `next` dist tag, rather than -`latest`, such as when creating a release candidate or testing a development -version, you can use the provided `publish:next` script. +If you would like to publish alpha release versions, for example `kyt@1.2.8-alpha.6`: ```sh -$ GH_TOKEN=$GITHUB_TOKEN npm run publish:next +$ GH_TOKEN=$GITHUB_TOKEN npm run publish:alpha ``` If you need more functionality than this, it is recommended that you pass your diff --git a/README.md b/README.md index 00edf8a19..1d2ecec69 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,14 @@ # kyt +### Deprecation notice + +This project is still used internally at the new york times but has long been deprecated. Please don't expect any support or documented releases going forward. + +--- + +--- + Every sizable JavaScript web app needs a common foundation: a setup to build, run, test and lint your code. `kyt` is a toolkit that encapsulates and manages the configuration for web apps. Read more about kyt in our [blog post](https://open.nytimes.com/introducing-kyt-our-web-app-configuration-toolkit-9ccddf6f6988). diff --git a/e2e_tests/tests/cli.test.js b/e2e_tests/tests/cli.test.js index bd756df73..5402bd9ad 100644 --- a/e2e_tests/tests/cli.test.js +++ b/e2e_tests/tests/cli.test.js @@ -26,9 +26,12 @@ describe('KYT CLI', () => { it(`sets up a ${slug} starter-kyt`, () => { const exec = new Promise(resolve => { shell.cd(rootPath); - const child = shell.exec('../packages/kyt-core/lib/index.js setup', (code, stdout) => { - resolve({ code, output: stdout }); - }); + const child = shell.exec( + 'NODE_OPTIONS=--openssl-legacy-provider ../packages/kyt-core/lib/index.js setup', + (code, stdout) => { + resolve({ code, output: stdout }); + } + ); let skdone = false; let chooseDone = false; let ypmDone = false; diff --git a/e2e_tests/tests/kyt-build.test.js b/e2e_tests/tests/kyt-build.test.js index 96d6dc92e..16833f4a1 100644 --- a/e2e_tests/tests/kyt-build.test.js +++ b/e2e_tests/tests/kyt-build.test.js @@ -10,7 +10,9 @@ describe('kyt build', () => { it('should compile files into a build directory', () => { util.setupStageWithFixture(stageName, 'build-default'); - const output = shell.exec('../packages/kyt-core/lib/index.js build'); + const output = shell.exec( + 'NODE_OPTIONS=--openssl-legacy-provider ../packages/kyt-core/lib/index.js build' + ); expect(shell.test('-f', 'build/publicAssets.json')).toBe(true); expect(shell.test('-d', 'build/server')).toBe(true); @@ -46,7 +48,7 @@ describe('kyt build', () => { it('should ignore server build if hasServer=false', () => { util.setupStageWithFixture(stageName, 'build-no-server'); - const output = shell.exec('npm run build'); + const output = shell.exec('NODE_OPTIONS=--openssl-legacy-provider npm run build'); expect(output.code).toBe(0); expect(shell.test('-d', 'build/server')).toBe(false); @@ -54,7 +56,7 @@ describe('kyt build', () => { it('should ignore client build if hasClient=false', () => { util.setupStageWithFixture(stageName, 'build-no-client'); - const output = shell.exec('npm run build'); + const output = shell.exec('NODE_OPTIONS=--openssl-legacy-provider npm run build'); expect(output.code).toBe(0); expect(shell.test('-d', 'build/server')).toBe(true); diff --git a/e2e_tests/tests/starter-kyt.test.js b/e2e_tests/tests/starter-kyt.test.js index 6e78c5435..c12844c20 100644 --- a/e2e_tests/tests/starter-kyt.test.js +++ b/e2e_tests/tests/starter-kyt.test.js @@ -19,7 +19,7 @@ describe('starter kyts', () => { it('should start a dev server on :3000', () => { let outputTest; const run = new Promise(resolve => { - const child = shell.exec(`${kytCli} dev`, () => { + const child = shell.exec(`NODE_OPTIONS=--openssl-legacy-provider ${kytCli} dev`, () => { resolve(outputTest); }); child.stdout.on('data', data => { @@ -38,11 +38,14 @@ describe('starter kyts', () => { it('should build and run', () => { let outputTest; - shell.exec(`${kytCli} build`); + shell.exec(`NODE_OPTIONS=--openssl-legacy-provider ${kytCli} build`); const run = new Promise(resolve => { - const child = shell.exec('node build/server/main.js', () => { - resolve(outputTest); - }); + const child = shell.exec( + 'NODE_OPTIONS=--openssl-legacy-provider node build/server/main.js', + () => { + resolve(outputTest); + } + ); child.stdout.on('data', data => { if (data.includes('✅ server started on port: 3000')) { shell.exec('sleep 5'); @@ -71,7 +74,7 @@ describe('starter kyts', () => { it('should start a server on :3001', () => { let outputTest; const run = new Promise(resolve => { - const child = shell.exec(`${kytCli} dev`, () => { + const child = shell.exec(`NODE_OPTIONS=--openssl-legacy-provider ${kytCli} dev`, () => { resolve(outputTest); }); child.stdout.on('data', data => { @@ -87,7 +90,7 @@ describe('starter kyts', () => { }); it('should build', () => { - const output = shell.exec(`${kytCli} build`); + const output = shell.exec(`NODE_OPTIONS=--openssl-legacy-provider ${kytCli} build`); expect(output.stdout).toContain('✅ Done building'); diff --git a/package.json b/package.json index bae36190e..39a704c60 100644 --- a/package.json +++ b/package.json @@ -15,11 +15,11 @@ "yarn": "^1" }, "scripts": { - "bootstrap": "yarn && lerna run prepare", + "bootstrap": "yarn && lerna bootstrap && lerna run prepare && lerna link", "bootstrap:ci": "yarn && lerna run prepare", "clean-bootstrap": "lerna clean --yes && rm -rf node_modules && yarn bootstrap", "publish": "lerna publish", - "publish:next": "lerna publish --preid next --dist-tag next", + "publish:alpha": "lerna publish --canary --force-publish --preid alpha --dist-tag alpha", "test:starter": "lerna exec --scope \"kyt-starter-{server,static,universal}-src\" --", "test": "lerna run prepare && jest --detectOpenHandles && yarn test:starter yarn test --detectOpenHandles", "test:ci": "jest --detectOpenHandles --ci && yarn test:starter yarn test --detectOpenHandles --ci", @@ -31,7 +31,10 @@ "lint-staged": "yarn run lint -o", "lint-fix": "ESLINT_FIX=1 ESLINT_QUIET=1 yarn run lint", "lint:ci": "ESLINT_QUIET=1 yarn run lint", - "watch-cli": "yarn workspace kyt watch", + "watch": "run-p watch-*", + "watch-kyt": "yarn workspace kyt watch", + "watch-kyt-runtime": "yarn workspace kyt-runtime watch", + "watch-kyt-utils": "yarn workspace kyt-utils watch", "prepare": "husky install" }, "devDependencies": { @@ -62,6 +65,7 @@ "jest-runner-eslint": "0.10.1", "jest-silent-reporter": "0.5.0", "lerna": "4.0.0", + "npm-run-all": "4.1.5", "prettier": "2.8.8", "react": "17.0.2", "react-dom": "17.0.2", diff --git a/packages/kyt-core/package.json b/packages/kyt-core/package.json index 05dd56fbc..e02fcf5ff 100644 --- a/packages/kyt-core/package.json +++ b/packages/kyt-core/package.json @@ -23,6 +23,7 @@ "babel-preset-kyt-core": "2.0.1", "commander": "8.2.0", "core-js": "3.18.0", + "css-loader": "5.2.7", "file-loader": "6.2.0", "filesize": "8.0.3", "find-babel-config": "1.2.0", @@ -36,23 +37,28 @@ "kyt-utils": "1.3.33", "lodash.clonedeep": "4.5.0", "lodash.merge": "4.6.2", + "mini-css-extract-plugin": "1.6.2", + "optimize-css-assets-webpack-plugin": "6.0.1", + "postcss-loader": "4.2.0", "prop-types": "15.7.2", "ps-tree": "1.2.0", "react": "17.0.2", "react-dev-utils": "11.0.4", "react-error-overlay": "6.0.9", "regenerator-runtime": "0.13.9", + "sass": "1.74.1", + "sass-loader": "10.2.0", "semver": "7.3.5", "shelljs": "0.8.5", "simple-git": "2.42.0", "sockjs-client": "1.5.2", "source-map-support": "0.5.20", "strip-ansi": "6.0.0", + "style-loader": "0.23.1", "url-loader": "4.1.1", "webpack": "4.46.0", "webpack-dev-server": "3.11.2", "webpack-merge": "4.2.2", - "webpack-node-externals": "2.5.2", "webpackbar": "4.0.0" }, "devDependencies": { diff --git a/packages/kyt-core/src/config/externals.js b/packages/kyt-core/src/config/externals.js new file mode 100644 index 000000000..f6b99276a --- /dev/null +++ b/packages/kyt-core/src/config/externals.js @@ -0,0 +1,53 @@ +// Works similarly to webpack-node-externals but it's not as +// aggressive. It only excludes top-level dependency-declared +// modules. Respects an `allowList` of regexp's that will be +// used to match modules to include in the bundle. +const { userPackageJSONPath } = require('kyt-utils/paths')(); + +let pkg; + +try { + // eslint-disable-next-line import/no-dynamic-require, global-require + pkg = require(userPackageJSONPath); +} catch (e) { + pkg = {}; +} + +module.exports = (allowList = []) => { + // Get all of the dependencies from the package.json + // and filter out the ones that are in the allowList + const packageModules = []; + Object.keys(pkg.dependencies || []).forEach(module => { + allowList.forEach(allowedModule => { + if (!allowedModule.test(module)) packageModules.push(module); + }); + }); + + return [ + // eslint-disable-next-line consistent-return + (context, request, callback) => { + function getModuleName(requested) { + const scopedModuleRegex = new RegExp( + '@[a-zA-Z0-9][\\w-.]+/[a-zA-Z0-9][\\w-.]+([a-zA-Z0-9./]+)?', + 'g' + ); + const req = requested; + const delimiter = '/'; + + // Check if scoped module. For example: @company/boring-module + if (scopedModuleRegex.test(req)) { + // reset regexp + scopedModuleRegex.lastIndex = 0; + return req.split(delimiter, 2).join(delimiter); + } + return req.split(delimiter)[0]; + } + if (packageModules.includes(getModuleName(request))) { + // Mark this module as EXTERNAL + return callback(null, `commonjs ${request}`); + } + // Include module in bundle / NOT EXTERNAL + callback(); + }, + ]; +}; diff --git a/packages/kyt-core/src/config/postcss.config.js b/packages/kyt-core/src/config/postcss.config.js new file mode 100644 index 000000000..4e2f8e188 --- /dev/null +++ b/packages/kyt-core/src/config/postcss.config.js @@ -0,0 +1,5 @@ +module.exports = { + postcssOptions: { + plugins: [['autoprefixer', {}]], + }, +}; diff --git a/packages/kyt-core/src/config/webpack.dev.client.js b/packages/kyt-core/src/config/webpack.dev.client.js index 7eb2f7a54..671bb335b 100644 --- a/packages/kyt-core/src/config/webpack.dev.client.js +++ b/packages/kyt-core/src/config/webpack.dev.client.js @@ -1,10 +1,13 @@ // Development webpack config for client code const path = require('path'); const webpack = require('webpack'); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const errorOverlayMiddleware = require('react-dev-utils/errorOverlayMiddleware'); const { kytWebpackPlugins } = require('kyt-runtime/webpack'); -const { clientSrcPath, assetsBuildPath, publicBuildPath } = require('kyt-utils/paths')(); +const { clientSrcPath, assetsBuildPath, publicBuildPath, publicSrcPath } = + require('kyt-utils/paths')(); const getPolyfill = require('./getPolyfill'); +const postcssLoader = require('../utils/getPostcssLoader'); module.exports = options => { const main = [ @@ -65,6 +68,40 @@ module.exports = options => { }, }, - plugins: [...kytWebpackPlugins(options), new webpack.HotModuleReplacementPlugin()], + module: { + rules: [ + { + test: /\.module\.(sc|c)ss$/, + use: [ + // 'style-loader', + MiniCssExtractPlugin.loader, + { + loader: 'css-loader', + options: { + sourceMap: true, + modules: { + localIdentName: '[name]-[local]--[hash:base64:5]', + // exportOnlyLocals: true, + }, + }, + }, + postcssLoader, + 'sass-loader', + ], + exclude: [publicSrcPath], + }, + ], + }, + + plugins: [ + ...kytWebpackPlugins(options), + new MiniCssExtractPlugin({ + // Options similar to the same options in webpackOptions.output + // both options are optional + filename: '[name].css', + chunkFilename: '[id].css', + }), + new webpack.HotModuleReplacementPlugin(), + ], }; }; diff --git a/packages/kyt-core/src/config/webpack.dev.server.js b/packages/kyt-core/src/config/webpack.dev.server.js index 60ad6fb36..68a904fa0 100644 --- a/packages/kyt-core/src/config/webpack.dev.server.js +++ b/packages/kyt-core/src/config/webpack.dev.server.js @@ -1,11 +1,12 @@ // Development webpack config for server code const webpack = require('webpack'); -const nodeExternals = require('webpack-node-externals'); -const { serverSrcPath, serverBuildPath, clientAssetsFile, loadableAssetsFile } = +const { serverSrcPath, serverBuildPath, clientAssetsFile, loadableAssetsFile, publicSrcPath } = require('kyt-utils/paths')(); const StartServerPlugin = require('./StartServerPlugin'); +const postcssLoader = require('../utils/getPostcssLoader'); const getPolyfill = require('./getPolyfill'); +const externals = require('./externals'); const nodeArgs = ['-r', 'source-map-support/register', '--max_old_space_size=4096']; // Passthrough --inspect and --inspect-brk flags (with optional [host:port] value) to node @@ -16,23 +17,6 @@ if (process.env.INSPECT_BRK) { } module.exports = options => { - let externals; - if (options.modulesDir && Array.isArray(options.modulesDir)) { - externals = options.modulesDir.map(dir => - nodeExternals({ - modulesDir: dir, - allowlist: ['webpack/hot/poll?300'], - }) - ); - } else { - externals = [ - nodeExternals({ - modulesDir: options.modulesDir, - allowlist: ['webpack/hot/poll?300'], - }), - ]; - } - return { mode: 'development', @@ -47,7 +31,9 @@ module.exports = options => { __filename: false, }, - externals, + externals: externals( + (options.externalModulesAllowlist || []).concat([/webpack\/hot\/poll\?300/]) + ), entry: { main: [ @@ -66,6 +52,28 @@ module.exports = options => { libraryTarget: 'commonjs2', }, + module: { + rules: [ + { + test: /\.module\.(sc|c)ss$/, + use: [ + { + loader: 'css-loader', + options: { + modules: { + localIdentName: '[name]-[local]--[hash:base64:5]', + exportOnlyLocals: true, + }, + }, + }, + postcssLoader, + 'sass-loader', + ], + exclude: [publicSrcPath], + }, + ], + }, + plugins: [ // Prevent creating multiple chunks for the server new webpack.optimize.LimitChunkCountPlugin({ diff --git a/packages/kyt-core/src/config/webpack.prod.client.js b/packages/kyt-core/src/config/webpack.prod.client.js index bb74e3e67..6edbc64db 100644 --- a/packages/kyt-core/src/config/webpack.prod.client.js +++ b/packages/kyt-core/src/config/webpack.prod.client.js @@ -1,7 +1,9 @@ // Production webpack config for client code - -const { clientSrcPath, assetsBuildPath } = require('kyt-utils/paths')(); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); +const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); +const { clientSrcPath, assetsBuildPath, publicSrcPath } = require('kyt-utils/paths')(); const { kytWebpackPlugins } = require('kyt-runtime/webpack'); +const postcssLoader = require('../utils/getPostcssLoader'); const getPolyfill = require('./getPolyfill'); module.exports = options => ({ @@ -22,7 +24,43 @@ module.exports = options => ({ publicPath: options.publicPath, }, - plugins: [...kytWebpackPlugins(options)], + module: { + rules: [ + { + test: /\.module\.(sc|c)ss$/, + use: [ + MiniCssExtractPlugin.loader, + { + loader: 'css-loader', + options: { + modules: { + localIdentName: '[name]-[local]--[hash:base64:5]', + }, + }, + }, + postcssLoader, + { + loader: 'sass-loader', + options: { + sourceMap: true, + }, + }, + ], + exclude: [publicSrcPath], + }, + ], + }, + + plugins: [ + ...kytWebpackPlugins(options), + + new MiniCssExtractPlugin({ + filename: '[name]-[contenthash].css', + chunkFilename: '[name]-[contenthash].css', + }), + + new OptimizeCSSAssetsPlugin({}), + ], optimization: { moduleIds: 'hashed', @@ -37,6 +75,14 @@ module.exports = options => ({ chunks: 'all', minChunks: 2, }, + styles: { + name: 'cssModulesStyles', + test: /\.module\.s?css$/, + chunks: 'all', + minChunks: 1, + reuseExistingChunk: true, + enforce: true, + }, }, }, }, diff --git a/packages/kyt-core/src/config/webpack.prod.server.js b/packages/kyt-core/src/config/webpack.prod.server.js index 659fd3d80..d5553cb79 100644 --- a/packages/kyt-core/src/config/webpack.prod.server.js +++ b/packages/kyt-core/src/config/webpack.prod.server.js @@ -1,39 +1,25 @@ // Production webpack config for server code const webpack = require('webpack'); -const nodeExternals = require('webpack-node-externals'); -const { serverSrcPath, serverBuildPath } = require('kyt-utils/paths')(); +const { serverSrcPath, serverBuildPath, publicSrcPath } = require('kyt-utils/paths')(); +const externals = require('./externals'); +const postcssLoader = require('../utils/getPostcssLoader'); const getPolyfill = require('./getPolyfill'); module.exports = options => { - let externals; - if (options.modulesDir && Array.isArray(options.modulesDir)) { - externals = options.modulesDir.map(dir => - nodeExternals({ - modulesDir: dir, - }) - ); - } else { - externals = [ - nodeExternals({ - modulesDir: options.modulesDir, - }), - ]; - } - return { mode: 'production', target: 'node', - devtool: 'source-map', + devtool: 'cheap-module-source-map', node: { __dirname: false, __filename: false, }, - externals, + externals: externals(options.externalModulesAllowlist), entry: { main: [getPolyfill(options.type), `${serverSrcPath}/index.js`].filter(Boolean), @@ -47,6 +33,28 @@ module.exports = options => { libraryTarget: 'commonjs2', }, + module: { + rules: [ + { + test: /\.module\.(sc|c)ss$/, + use: [ + { + loader: 'css-loader', + options: { + modules: { + localIdentName: '[name]-[local]--[hash:base64:5]', + exportOnlyLocals: true, + }, + }, + }, + postcssLoader, + 'sass-loader', + ], + exclude: [publicSrcPath], + }, + ], + }, + plugins: [ new webpack.BannerPlugin({ banner: 'require("source-map-support").install();', diff --git a/packages/kyt-core/src/utils/buildConfigs.js b/packages/kyt-core/src/utils/buildConfigs.js index 3658d158e..e02d6bec2 100644 --- a/packages/kyt-core/src/utils/buildConfigs.js +++ b/packages/kyt-core/src/utils/buildConfigs.js @@ -17,7 +17,7 @@ const prodClientConfig = require('../config/webpack.prod.client'); const prodServerConfig = require('../config/webpack.prod.server'); module.exports = (config, environment = 'development') => { - const { clientURL, serverURL, modulesDir } = config; + const { clientURL, serverURL, externalModulesAllowlist } = config; let clientConfig = devClientConfig; let serverConfig = devServerConfig; @@ -41,7 +41,10 @@ module.exports = (config, environment = 'development') => { }); } - const serverOptions = merge(clientOptions, { type: 'server', modulesDir }); + const serverOptions = merge(clientOptions, { + type: 'server', + externalModulesAllowlist, + }); const hasBabelrc = findBabelConfigSync(userRootPath); if (!hasBabelrc || !hasBabelrc.config) { diff --git a/packages/kyt-core/src/utils/getPostcssLoader.js b/packages/kyt-core/src/utils/getPostcssLoader.js new file mode 100644 index 000000000..288eb305a --- /dev/null +++ b/packages/kyt-core/src/utils/getPostcssLoader.js @@ -0,0 +1,21 @@ +const fs = require('fs'); +const { userPostcssConfigPath } = require('kyt-utils/paths')(); +const logger = require('kyt-utils/logger'); +const kytPostcssConfig = require('../config/postcss.config'); + +// We either use the kyt postcss.config.js or we use an +// override from the user. +const postcssConfig = { loader: 'postcss-loader' }; +const userHasPostcssConfig = fs.existsSync(userPostcssConfigPath); + +if (userHasPostcssConfig) { + logger.info(`Using postcss config: ${userPostcssConfigPath}`); + // eslint-disable-next-line global-require,import/no-dynamic-require + const userPostcssConfig = require(userPostcssConfigPath); + postcssConfig.options = + typeof userPostcssConfig === 'function' ? userPostcssConfig() : userPostcssConfig; +} else { + postcssConfig.options = kytPostcssConfig; +} + +module.exports = postcssConfig; diff --git a/packages/kyt-runtime/package.json b/packages/kyt-runtime/package.json index 8589c41be..c43daff0b 100644 --- a/packages/kyt-runtime/package.json +++ b/packages/kyt-runtime/package.json @@ -31,6 +31,7 @@ "babel-preset-kyt-core": "2.0.1" }, "scripts": { + "watch": "yarn prepare --watch", "prepare": "rimraf lib && babel src -d lib --ignore \"**/__tests__/**\"" }, "gitHead": "a120343756f132868e6af0cfee3579bfc3dafaa8" diff --git a/packages/kyt-runtime/src/server.js b/packages/kyt-runtime/src/server.js index 40d61eb48..8d2cf3046 100644 --- a/packages/kyt-runtime/src/server.js +++ b/packages/kyt-runtime/src/server.js @@ -21,12 +21,16 @@ export const getBundles = ({ entry = 'main', modules, assets = null, loadableBun const runtimeBundle = assets[`runtime~${entry}.js`]; const entryBundle = assets[`${entry}.js`]; const vendorBundle = assets['vendor.js']; + const cssModulesStyles = assets['cssModulesStyles.css'] || assets[`${entry}.css`]; + const cssModulesBundle = assets['cssModulesStyles.js']; const bundleManifest = { runtimeBundle, entryBundle, vendorBundle, scripts: [], + cssModulesStyles, + cssModulesBundle, }; if (!modules || modules.length === 0) { @@ -40,11 +44,14 @@ export const getBundles = ({ entry = 'main', modules, assets = null, loadableBun let hashes = []; loadableBundles.entries.forEach(key => { - hashes = hashes.concat([assets[`${key}.js`]]).filter(Boolean); + hashes = hashes.concat([assets[`${key}.js`], assets[`${key}.css`]]).filter(Boolean); }); const bundles = getLoadableBundles(loadableBundles.bundles, modules); + const cssBundles = bundles.filter(b => b.file.endsWith('.css') && !hashes.includes(b.publicPath)); + bundleManifest.styles = [...new Set(cssBundles.map(b => b.publicPath))]; + const jsBundles = bundles.filter( b => b?.file?.endsWith('.js') && diff --git a/packages/kyt-starter-universal/starter-src/package.json b/packages/kyt-starter-universal/starter-src/package.json index a8d1b3281..c4afb0a13 100644 --- a/packages/kyt-starter-universal/starter-src/package.json +++ b/packages/kyt-starter-universal/starter-src/package.json @@ -56,6 +56,7 @@ "eslint-plugin-prettier": "3.4.1", "eslint-plugin-react": "7.26.0", "eslint-plugin-react-hooks": "4.2.0", + "identity-obj-proxy": "3.0.0", "jest": "27.2.1", "jest-preset-kyt-rtl": "1.1.2", "jest-preset-kyt-styled": "1.4.12", diff --git a/packages/kyt-starter-universal/starter-src/src/components/App/__snapshots__/index.test.js.snap b/packages/kyt-starter-universal/starter-src/src/components/App/__snapshots__/index.test.js.snap index 13551ea30..3728a3ef2 100644 --- a/packages/kyt-starter-universal/starter-src/src/components/App/__snapshots__/index.test.js.snap +++ b/packages/kyt-starter-universal/starter-src/src/components/App/__snapshots__/index.test.js.snap @@ -1,28 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`App Test home route 1`] = ` -.lights-5 { - width: 500px; - margin: 0 auto; - padding: 15px; - text-align: center; -} - -.lights-8 { - width: 500px; - margin: 15px auto; -} - -.lights-2 { - display: inline-block; -} - -.lights-1 { - padding: 15px; - color: #00a68f; - font-size: 18px; -} - .lights-0 { display: block; width: 252px; @@ -31,7 +9,7 @@ exports[`App Test home route 1`] = ` background: url(file-stub); } -.lights-6 + .lights-6 { +.lights-1 + .lights-1 { padding-top: 15px; } @@ -40,23 +18,23 @@ exports[`App Test home route 1`] = ` class="lights-0" />

Welcome to the @@ -77,7 +55,7 @@ exports[`App Test home route 1`] = ` . This starter kyt should serve as the base for an advanced, server-rendered React app.

Check out the Tools section for an outline of the libraries that are used in this Starter-kyt.

@@ -93,28 +71,6 @@ Array [ `; exports[`App Test tools route 1`] = ` -.lights-5 { - width: 500px; - margin: 0 auto; - padding: 15px; - text-align: center; -} - -.lights-11 { - width: 500px; - margin: 15px auto; -} - -.lights-2 { - display: inline-block; -} - -.lights-1 { - padding: 15px; - color: #00a68f; - font-size: 18px; -} - .lights-0 { display: block; width: 252px; @@ -123,7 +79,7 @@ exports[`App Test tools route 1`] = ` background: url(file-stub); } -.lights-6 + .lights-6 { +.lights-1 + .lights-1 { padding-top: 5px; } @@ -132,23 +88,23 @@ exports[`App Test tools route 1`] = ` class="lights-0" />