@epic-effx/create-application-template-rs 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/.babelrc +14 -0
  2. package/.browserslistrc +3 -0
  3. package/.codex +0 -0
  4. package/.eslintrc.js +309 -0
  5. package/.husky/pre-commit +5 -0
  6. package/.stylelintrc.js +29 -0
  7. package/LICENSE +21 -0
  8. package/README.md +141 -0
  9. package/bin/create-application-template-rs.js +116 -0
  10. package/jest/cssTransform.js +13 -0
  11. package/jest/fontTransform.js +12 -0
  12. package/jest/setup.js +5 -0
  13. package/jest/setupTests.js +15 -0
  14. package/jest/svgTransform.js +12 -0
  15. package/jest.config.js +58 -0
  16. package/package.json +117 -0
  17. package/rspack/rspack.common.js +212 -0
  18. package/rspack/rspack.config.js +14 -0
  19. package/rspack/rspack.dev.js +36 -0
  20. package/rspack/rspack.prod.js +43 -0
  21. package/rspack/utilities/createEnvironmentHash.js +8 -0
  22. package/rspack/utilities/env.js +8 -0
  23. package/rspack/utilities/generateAssetManifest.js +16 -0
  24. package/rspack/utilities/getPaths.js +57 -0
  25. package/rspack/utilities/getTerserOptions.js +47 -0
  26. package/scripts/generate-sitemap.ts +25 -0
  27. package/src/app.d.ts +7 -0
  28. package/src/assets/favicon.ico +0 -0
  29. package/src/assets/logo.svg +15 -0
  30. package/src/components/App.spec.tsx +24 -0
  31. package/src/components/App.tsx +66 -0
  32. package/src/components/Counter.spec.tsx +38 -0
  33. package/src/components/Counter.tsx +26 -0
  34. package/src/components/Typewriter.spec.tsx +36 -0
  35. package/src/components/Typewriter.tsx +66 -0
  36. package/src/components/__snapshots__/App.spec.tsx.snap +56 -0
  37. package/src/components/__snapshots__/Counter.spec.tsx.snap +44 -0
  38. package/src/components/__snapshots__/Typewriter.spec.tsx.snap +56 -0
  39. package/src/fonts/Exo2-Regular.woff2 +0 -0
  40. package/src/fonts/Orbitron-Regular.woff2 +0 -0
  41. package/src/index.html +18 -0
  42. package/src/index.tsx +12 -0
  43. package/src/public/robots.txt +6 -0
  44. package/src/styles/App.styled.ts +42 -0
  45. package/src/styles/Counter.styled.ts +30 -0
  46. package/src/styles/Global.ts +18 -0
  47. package/src/styles/Logo.styled.ts +24 -0
  48. package/src/styles/Typewriter.styled.ts +5 -0
  49. package/src/styles/env.css +11 -0
  50. package/src/styles/theme.ts +21 -0
  51. package/tsconfig.json +31 -0
@@ -0,0 +1,15 @@
1
+ require('dotenv-flow').config()
2
+
3
+ // additional jest matchers
4
+ // https://jest-extended.jestcommunity.dev/docs/matchers
5
+ const matchers = require('jest-extended')
6
+ expect.extend(matchers)
7
+
8
+ // custom jest matchers for asserting on DOM nodes
9
+ // https://www.npmjs.com/package/@testing-library/jest-dom
10
+ require('@testing-library/jest-dom')
11
+ // require('@testing-library/jest-dom/jest-globals')
12
+
13
+ afterEach(() => {
14
+ jest.useRealTimers()
15
+ })
@@ -0,0 +1,12 @@
1
+ // turning svg imports into empty objects
2
+
3
+ module.exports = {
4
+ process() {
5
+ return {
6
+ code: 'module.exports = {}',
7
+ }
8
+ },
9
+ getCacheKey() {
10
+ return 'svgTransform'
11
+ },
12
+ }
package/jest.config.js ADDED
@@ -0,0 +1,58 @@
1
+ /** @returns {Promise<import('jest').Config>} */
2
+ module.exports = async () => {
3
+ return {
4
+ rootDir: __dirname,
5
+ roots: [
6
+ '<rootDir>/src',
7
+ ],
8
+ automock: false,
9
+ collectCoverage: true,
10
+ collectCoverageFrom: [
11
+ 'src/**/*.{js,jsx,ts,tsx}',
12
+ '!**/node_modules/**',
13
+ 'src/**/*.d.ts',
14
+ ],
15
+ coverageDirectory: '<rootDir>/jest/coverage',
16
+ coverageThreshold: undefined,
17
+ displayName: 'UI',
18
+ globals: {},
19
+ maxConcurrency: 5, // 5 is default (see test.concurrent)
20
+ moduleNameMapper: {
21
+ '^.+\\.module\\.(css)$': 'identity-obj-proxy',
22
+ },
23
+ resetMocks: true,
24
+ setupFiles: [
25
+ '<rootDir>/jest/setup.js',
26
+ ],
27
+ setupFilesAfterEnv: [
28
+ '<rootDir>/jest/setupTests.js',
29
+ ],
30
+ testMatch: [
31
+ '<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}',
32
+ ],
33
+ testEnvironment: 'jsdom',
34
+ transform: {
35
+ '^.+\\.(t|j)sx?$': ['@swc/jest', {
36
+ jsc: {
37
+ transform: {
38
+ react: {
39
+ runtime: 'automatic',
40
+ },
41
+ },
42
+ },
43
+ }],
44
+ '^.+\\.css$': '<rootDir>/jest/cssTransform.js',
45
+ '^.+\\.svg$': '<rootDir>/jest/svgTransform.js',
46
+ '^.+\\.woff2$': '<rootDir>/jest/fontTransform.js',
47
+ },
48
+ // transformIgnorePatterns: [
49
+ // '[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs|cjs|ts|tsx)$',
50
+ // '^.+\\.module\\.(css|sass|scss)$',
51
+ // ],
52
+ verbose: true,
53
+ watchPlugins: [
54
+ 'jest-watch-typeahead/filename',
55
+ 'jest-watch-typeahead/testname',
56
+ ],
57
+ }
58
+ }
package/package.json ADDED
@@ -0,0 +1,117 @@
1
+ {
2
+ "name": "@epic-effx/create-application-template-rs",
3
+ "version": "0.1.0",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "create-application-template-rs": "bin/create-application-template-rs.js"
8
+ },
9
+ "scripts": {
10
+ "start": "cross-env NODE_ENV=development SWC_ENV=development BABEL_ENV=development rspack serve --config rspack/rspack.config.js --env BUNDLER_ENV=dev",
11
+ "build": "cross-env NODE_ENV=production SWC_ENV=production BABEL_ENV=production rspack --config rspack/rspack.config.js --env BUNDLER_ENV=prod BUNDLER_WITH_PROFILING=false",
12
+ "build:profile": "cross-env NODE_ENV=production SWC_ENV=production BABEL_ENV=production rspack --config rspack/rspack.config.js --env BUNDLER_ENV=prod BUNDLER_WITH_PROFILING=true",
13
+ "test": "jest",
14
+ "test:watch": "jest --watch",
15
+ "test:updateSnapshot": "jest --updateSnapshot",
16
+ "dev": "concurrently \"npm run test:watch\" \"npm run start\"",
17
+ "lint": "eslint \"src/**/*.{js,jsx,ts,tsx,json}\"",
18
+ "lint:fix": "eslint --fix \"src/**/*.{js,jsx,ts,tsx,json}\"",
19
+ "stylelint": "npx stylelint \"src/styles/**/*.{js,ts}\"",
20
+ "stylelint:fix": "npx stylelint --fix \"src/styles/**/*.{js,ts}\"",
21
+ "stylelint:css": "npx stylelint \"src/**/*.css\"",
22
+ "stylelint:css:fix": "npx stylelint --fix \"src/**/*.css\""
23
+ },
24
+ "keywords": [
25
+ "template",
26
+ "react",
27
+ "typescript",
28
+ "styled-components",
29
+ "rspack",
30
+ "swc",
31
+ "jest",
32
+ "eslint",
33
+ "stylelint",
34
+ "javascript"
35
+ ],
36
+ "url": "https://www.createapplicationtemplaters.com/",
37
+ "author": "",
38
+ "license": "MIT",
39
+ "proxy": "http://localhost:3000",
40
+ "engines": {
41
+ "node": ">=20",
42
+ "npm": ">=10"
43
+ },
44
+ "overrides": {
45
+ "serialize-javascript": "7.0.3"
46
+ },
47
+ "templateMeta": {
48
+ "overridesNote": "overrides patch known transitive vulnerabilities in tooling; safe within same major; remove once upstream ranges are updated."
49
+ },
50
+ "dependencies": {
51
+ "browserslist": "4.24.4",
52
+ "concurrently": "9.1.2",
53
+ "cross-env": "10.1.0",
54
+ "dotenv-flow": "4.1.0",
55
+ "husky": "9.1.7",
56
+ "polished": "4.3.1",
57
+ "react": "19.1.1",
58
+ "react-dom": "19.1.1",
59
+ "styled-components": "6.1.15"
60
+ },
61
+ "devDependencies": {
62
+ "@babel/core": "7.26.9",
63
+ "@babel/preset-react": "7.26.3",
64
+ "@babel/preset-typescript": "7.26.0",
65
+ "@rspack/cli": "1.7.9",
66
+ "@rspack/core": "1.7.9",
67
+ "@rspack/plugin-react-refresh": "1.6.1",
68
+ "@swc/helpers": "0.5.20",
69
+ "@swc/jest": "0.2.39",
70
+ "@swc/plugin-styled-components": "12.7.0",
71
+ "@testing-library/jest-dom": "6.9.1",
72
+ "@testing-library/react": "16.2.0",
73
+ "@testing-library/user-event": "14.6.1",
74
+ "@types/jest": "30.0.0",
75
+ "@types/node": "20.12.12",
76
+ "@types/react": "19.1.13",
77
+ "@types/react-dom": "19.1.9",
78
+ "@types/styled-components": "5.1.34",
79
+ "@typescript-eslint/eslint-plugin": "6.5.0",
80
+ "@typescript-eslint/parser": "6.5.0",
81
+ "babel-loader": "10.0.0",
82
+ "babel-plugin-react-compiler": "19.1.0-rc.3",
83
+ "case-sensitive-paths-webpack-plugin": "2.4.0",
84
+ "confusing-browser-globals": "1.0.11",
85
+ "css-loader": "7.1.2",
86
+ "css-minimizer-webpack-plugin": "7.0.4",
87
+ "dotenv-webpack": "8.1.0",
88
+ "eslint": "8.57.1",
89
+ "eslint-plugin-compat": "6.0.2",
90
+ "eslint-plugin-eslint-comments": "3.2.0",
91
+ "eslint-plugin-import": "2.31.0",
92
+ "eslint-plugin-jsx-a11y": "6.10.2",
93
+ "eslint-plugin-react": "7.37.4",
94
+ "eslint-plugin-react-hooks": "6.0.0-rc.2",
95
+ "html-webpack-plugin": "5.6.3",
96
+ "identity-obj-proxy": "3.0.0",
97
+ "jest": "30.2.0",
98
+ "jest-environment-jsdom": "30.2.0",
99
+ "jest-extended": "7.0.0",
100
+ "jest-styled-components": "7.2.0",
101
+ "jest-watch-typeahead": "3.0.1",
102
+ "postcss-styled-components": "0.2.1",
103
+ "react-refresh": "0.16.0",
104
+ "rspack-manifest-plugin": "5.2.1",
105
+ "style-loader": "4.0.0",
106
+ "stylelint": "16.15.0",
107
+ "stylelint-config-recess-order": "6.0.0",
108
+ "stylelint-config-standard": "36.0.0",
109
+ "stylelint-no-unsupported-browser-features": "8.0.4",
110
+ "terser-webpack-plugin": "5.3.16",
111
+ "ts-node": "10.9.2",
112
+ "typescript": "5.8.2",
113
+ "webpack-merge": "6.0.1",
114
+ "webpack-shell-plugin-next": "2.3.2",
115
+ "whatwg-fetch": "3.6.20"
116
+ }
117
+ }
@@ -0,0 +1,212 @@
1
+ const fs = require('fs')
2
+ const { rspack } = require('@rspack/core')
3
+ const HtmlWebpackPlugin = require('html-webpack-plugin')
4
+ const Dotenv = require('dotenv-webpack')
5
+ const { RspackManifestPlugin } = require('rspack-manifest-plugin')
6
+ const env = require('./utilities/env')
7
+ const getPaths = require('./utilities/getPaths')
8
+ const createEnvironmentHash = require('./utilities/createEnvironmentHash')
9
+ const generateAssetManifest = require('./utilities/generateAssetManifest')
10
+
11
+ // styles regexps
12
+ const reCss = /\.css$/
13
+ const reCssModule = /\.module\.css$/
14
+
15
+ module.exports = (rspackEnv) => {
16
+ const { BUNDLER_ENV } = rspackEnv
17
+ const { INLINE_SIZE_LIMIT } = process.env
18
+
19
+ const paths = getPaths({ BUNDLER_ENV })
20
+
21
+ // NOTE it's preferable to isolate settings in appropriate
22
+ // files, but it's not always practical, hence "isProduction"
23
+ const isProduction = (BUNDLER_ENV === env.BUNDLER_ENV.prod)
24
+ const isDevelopment = (BUNDLER_ENV === env.BUNDLER_ENV.dev)
25
+
26
+ const styleLoaders = [
27
+ ...(isProduction
28
+ ? [{
29
+ loader: rspack.CssExtractRspackPlugin.loader, // MiniCssExtractPlugin.loader,
30
+ options: {
31
+ // css is located in 'static/css', use publicPath
32
+ // to locate index.html directory relative to css
33
+ publicPath: '../../',
34
+ },
35
+ }]
36
+ : ['style-loader']
37
+ ),
38
+ ]
39
+
40
+ return {
41
+ entry: paths.src.indexTsx,
42
+ resolve: {
43
+ // can now leave off extensions when importing
44
+ extensions: ['.tsx', '.jsx', '.ts', '.js'],
45
+ tsConfig: paths.tsconfigJson,
46
+ },
47
+ watchOptions: {
48
+ ignored: ['**/node_modules'],
49
+ },
50
+ module: {
51
+ rules: [
52
+ {
53
+ test: /\.(j|t)s$/,
54
+ exclude: [/[\\/]node_modules[\\/]/],
55
+ loader: 'builtin:swc-loader',
56
+ options: {
57
+ jsc: {
58
+ parser: {
59
+ syntax: 'typescript',
60
+ },
61
+ externalHelpers: true,
62
+ transform: {
63
+ react: {
64
+ runtime: 'automatic',
65
+ development: isDevelopment,
66
+ refresh: isDevelopment,
67
+ },
68
+ },
69
+ },
70
+ env: {
71
+ targets: 'Chrome >= 48', // browser compatibility
72
+ },
73
+ },
74
+ },
75
+ {
76
+ test: /\.(j|t)sx$/,
77
+ exclude: [/[\\/]node_modules[\\/]/],
78
+ use: [
79
+ {
80
+ loader: 'builtin:swc-loader',
81
+ options: {
82
+ jsc: {
83
+ parser: {
84
+ syntax: 'typescript',
85
+ tsx: true,
86
+ },
87
+ transform: {
88
+ react: {
89
+ runtime: 'automatic',
90
+ development: isDevelopment,
91
+ refresh: isDevelopment,
92
+ },
93
+ },
94
+ externalHelpers: true,
95
+ experimental: {
96
+ plugins: [
97
+ ['@swc/plugin-styled-components', {
98
+ displayName: true,
99
+ ssr: true,
100
+ fileName: true,
101
+ }],
102
+ ],
103
+ },
104
+ },
105
+ env: {
106
+ targets: 'Chrome >= 48',
107
+ },
108
+ },
109
+ },
110
+ // NOTE see docs for usage of React Compiler via babel
111
+ // https://rspack.rs/guide/tech/react#react-compiler
112
+ {
113
+ loader: 'babel-loader',
114
+ options: {
115
+ cacheDirectory: true,
116
+ cacheCompression: false,
117
+ compact: isProduction,
118
+ },
119
+ },
120
+ ],
121
+ },
122
+ {
123
+ test: reCss,
124
+ use: [...styleLoaders, 'css-loader'],
125
+ exclude: reCssModule,
126
+ },
127
+ {
128
+ test: reCssModule,
129
+ use: [
130
+ ...styleLoaders,
131
+ {
132
+ loader: 'css-loader',
133
+ options: {
134
+ importLoaders: 1,
135
+ modules: true,
136
+ },
137
+ },
138
+ ],
139
+ },
140
+ {
141
+ test: /\.(?:ico|gif|png|jpg|jpeg)$/i,
142
+ type: 'asset/resource',
143
+ },
144
+ {
145
+ test: /\.(woff(2)?|eot|ttf|otf|svg)$/,
146
+ type: 'asset',
147
+ parser: {
148
+ dataUrlCondition: {
149
+ maxSize: parseInt(INLINE_SIZE_LIMIT || 10000),
150
+ },
151
+ },
152
+ },
153
+ ],
154
+ },
155
+ output: {
156
+ path: paths.build,
157
+ pathinfo: isProduction ? false : true,
158
+ filename: paths.static.js.filenameJs,
159
+ chunkFilename: paths.static.js.chunkFilenameJs,
160
+ asyncChunks: true,
161
+ clean: true,
162
+ assetModuleFilename: paths.static.media.filenameExt,
163
+ publicPath: '', // public url of build, use in build/index.html
164
+ },
165
+ cache: { // used in development mode
166
+ type: 'filesystem',
167
+ version: createEnvironmentHash({ processEnv: process.env }),
168
+ cacheDirectory: paths.appWebpackCache,
169
+ store: 'pack',
170
+ buildDependencies: {
171
+ defaultWebpack: ['webpack/lib/'],
172
+ config: [__filename],
173
+ tsconfig: [paths.tsconfigJson, paths.jsconfigJson].filter(file =>
174
+ fs.existsSync(file)
175
+ ),
176
+ },
177
+ },
178
+ plugins: [
179
+ new HtmlWebpackPlugin({
180
+ template: paths.src.indexHtml,
181
+ favicon: paths.src.assets.faviconIco,
182
+ title: 'Create Application Template RS',
183
+ ...(isProduction && {
184
+ minify: {
185
+ removeComments: true,
186
+ collapseWhitespace: true,
187
+ removeRedundantAttributes: true,
188
+ useShortDoctype: true,
189
+ removeEmptyAttributes: true,
190
+ removeStyleLinkTypeAttributes: true,
191
+ keepClosingSlash: true,
192
+ minifyJS: true,
193
+ minifyCSS: true,
194
+ minifyURLs: true,
195
+ },
196
+ }),
197
+ }),
198
+ new RspackManifestPlugin({
199
+ fileName: 'asset-manifest.json',
200
+ publicPath: '/',
201
+ generate: generateAssetManifest,
202
+ }),
203
+ new rspack.CopyRspackPlugin({
204
+ patterns: [{
205
+ from: paths.src.public,
206
+ to: paths.build,
207
+ }],
208
+ }),
209
+ new Dotenv(),
210
+ ],
211
+ }
212
+ }
@@ -0,0 +1,14 @@
1
+ const { merge } = require('webpack-merge')
2
+ const commonConfig = require('./rspack.common.js')
3
+
4
+ require('dotenv-flow').config()
5
+
6
+ module.exports = (rspackEnv) => {
7
+ const { BUNDLER_ENV } = rspackEnv
8
+
9
+ const envConfig = require(`./rspack.${BUNDLER_ENV}.js`)
10
+
11
+ const config = merge(commonConfig(rspackEnv), envConfig(rspackEnv))
12
+
13
+ return config
14
+ }
@@ -0,0 +1,36 @@
1
+ const { rspack } = require('@rspack/core')
2
+ const ReactRefreshPlugin = require('@rspack/plugin-react-refresh')
3
+ const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin')
4
+ const packageJson = require('../package.json')
5
+
6
+ module.exports = () => {
7
+ const { PORT } = process.env
8
+
9
+ return {
10
+ mode: 'development', // NODE_ENV
11
+ devtool: 'cheap-module-source-map',
12
+ devServer: {
13
+ // static: {
14
+ // directory: paths.build,
15
+ // },
16
+ hot: true,
17
+ open: true,
18
+ port: PORT || 3333,
19
+ proxy: [
20
+ {
21
+ context: ['/'],
22
+ target: packageJson.proxy,
23
+ },
24
+ ],
25
+ historyApiFallback: true,
26
+ },
27
+ plugins: [
28
+ new rspack.DefinePlugin({
29
+ 'process.env.EXAMPLE': JSON.stringify('devconfig'),
30
+ }),
31
+ new ReactRefreshPlugin(),
32
+ new rspack.HotModuleReplacementPlugin(),
33
+ new CaseSensitivePathsPlugin(),
34
+ ],
35
+ }
36
+ }
@@ -0,0 +1,43 @@
1
+ const { rspack } = require('@rspack/core')
2
+ const TerserPlugin = require('terser-webpack-plugin')
3
+ const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
4
+ const WebpackShellPluginNext =require('webpack-shell-plugin-next')
5
+ const getPaths = require('./utilities/getPaths')
6
+ const getTerserOptions = require('./utilities/getTerserOptions')
7
+
8
+ module.exports = (rspackEnv) => {
9
+ const { BUNDLER_ENV, BUNDLER_WITH_PROFILING } = rspackEnv
10
+
11
+ const paths = getPaths({ BUNDLER_ENV })
12
+ const terserOptions = getTerserOptions({ BUNDLER_WITH_PROFILING })
13
+
14
+ return {
15
+ mode: 'production', // NODE_ENV
16
+ devtool: 'source-map',
17
+ optimization: {
18
+ minimize: true,
19
+ minimizer: [
20
+ new TerserPlugin({ terserOptions }), // TODO investigate SwcJsMinimizerRspackPlugin
21
+ new CssMinimizerPlugin(), // TODO investigate LightningCssMinimizerRspackPlugin
22
+ ],
23
+ },
24
+ plugins: [
25
+ new rspack.DefinePlugin({
26
+ 'process.env.EXAMPLE': JSON.stringify('prodconfig'),
27
+ }),
28
+ new rspack.CssExtractRspackPlugin({ // new MiniCssExtractPlugin({
29
+ filename: paths.static.css.filenameCss,
30
+ chunkFilename: paths.static.css.chunkFilenameCss,
31
+ }),
32
+ // TODO watch list to see if WebpackShellPluginNext gets added:
33
+ // https://rspack.rs/guide/compatibility/plugin#plugin-compatibility
34
+ new WebpackShellPluginNext({
35
+ onBuildStart: {
36
+ scripts: ['ts-node scripts/generate-sitemap.ts'],
37
+ blocking: true,
38
+ parallel: false,
39
+ },
40
+ }),
41
+ ],
42
+ }
43
+ }
@@ -0,0 +1,8 @@
1
+ const { createHash } = require('crypto')
2
+
3
+ module.exports = ({ processEnv }) => {
4
+ const hash = createHash('md5')
5
+ hash.update(JSON.stringify(processEnv))
6
+
7
+ return hash.digest('hex')
8
+ }
@@ -0,0 +1,8 @@
1
+ // NOTE passed in via webpack --env
2
+
3
+ module.exports = Object.freeze({
4
+ BUNDLER_ENV: {
5
+ prod: 'prod',
6
+ dev: 'dev',
7
+ },
8
+ })
@@ -0,0 +1,16 @@
1
+ module.exports = (seed, files, entrypoints) => {
2
+ const manifestFiles = files.reduce((manifest, file) => {
3
+ manifest[file.name] = file.path
4
+
5
+ return manifest
6
+ }, seed)
7
+
8
+ const entrypointFiles = entrypoints.main.filter(
9
+ fileName => !fileName.endsWith('.map')
10
+ )
11
+
12
+ return {
13
+ files: manifestFiles,
14
+ entrypoints: entrypointFiles,
15
+ }
16
+ }
@@ -0,0 +1,57 @@
1
+ const path = require('path')
2
+ const env = require('./env')
3
+
4
+ // NOTE root path assumes execution from react app root
5
+
6
+ const getPaths = ({ BUNDLER_ENV }) => {
7
+ const isProduction = (BUNDLER_ENV === env.BUNDLER_ENV.prod)
8
+
9
+ return {
10
+ root: process.cwd(),
11
+ get jsconfigJson() { return path.join(this.root, 'jsconfig.json') },
12
+ get tsconfigJson() { return path.join(this.root, 'tsconfig.json') },
13
+ get build() { return path.join(this.root, 'build') },
14
+ static: {
15
+ static: 'static',
16
+ get css() {
17
+ return {
18
+ css: path.join(this.static, 'css'),
19
+ get filenameCss() { return path.join(this.css, '[name].[contenthash].css') },
20
+ get chunkFilenameCss() { return path.join(this.css, '[name].[contenthash].chunk.css') },
21
+ }
22
+ },
23
+ get js() {
24
+ const filenameJs = isProduction ? '[name].[contenthash].js' : '[name].js'
25
+ const chunkFilenameJs = isProduction ? '[name].[contenthash].chunk.js' : '[name].chunk.js'
26
+
27
+ return {
28
+ js: path.join(this.static, 'js'),
29
+ get filenameJs() { return path.join(this.js, filenameJs) },
30
+ get chunkFilenameJs() { return path.join(this.js, chunkFilenameJs) },
31
+ }
32
+ },
33
+ get media() {
34
+ return {
35
+ media: path.join(this.static, 'media'),
36
+ get filenameExt() { return path.join(this.media, '[name].[hash][ext]') },
37
+ }
38
+ },
39
+ },
40
+ get src() {
41
+ return {
42
+ src: path.join(this.root, 'src'),
43
+ get indexTsx() { return path.join(this.src, 'index.tsx') },
44
+ get indexHtml() { return path.join(this.src, 'index.html') },
45
+ get public() { return path.join(this.src, 'public') },
46
+ get assets() {
47
+ return {
48
+ assets: path.join(this.src, 'assets'),
49
+ get faviconIco() { return path.join(this.assets, 'favicon.ico') },
50
+ }
51
+ },
52
+ }
53
+ },
54
+ }
55
+ }
56
+
57
+ module.exports = getPaths
@@ -0,0 +1,47 @@
1
+ // NOTE npm module react-scripts' options where the starting point,
2
+ // comments marked with :rs: are paraphrased from react-scripts
3
+
4
+ module.exports = ({ BUNDLER_WITH_PROFILING }) => {
5
+ const withProfiling = (BUNDLER_WITH_PROFILING)
6
+
7
+ return {
8
+ parse: {
9
+ // :rs: want terser to parse ecma 8 code however, don't want it
10
+ // to apply minification steps that turns valid ecma 5 code
11
+ // into invalid ecma 5 code... this is also why compress and
12
+ // output only apply transformations that are ecma 5 safe
13
+ // https://github.com/facebook/create-react-app/pull/4234
14
+ ecma: 8,
15
+ },
16
+ compress: {
17
+ ecma: 5,
18
+ warnings: false,
19
+ // :rs: disabled b/c of an issue with Uglify breaking seemingly valid code:
20
+ // https://github.com/facebook/create-react-app/issues/2376
21
+ // pending further investigation:
22
+ // https://github.com/mishoo/UglifyJS2/issues/2011
23
+ comparisons: false,
24
+ // :rs: disabled because of an issue with Terser breaking valid code:
25
+ // https://github.com/facebook/create-react-app/issues/5250
26
+ // pending further investigation:
27
+ // https://github.com/terser-js/terser/issues/120
28
+ inline: 2,
29
+ },
30
+ mangle: {
31
+ // to work around the Safari 10 loop iterator
32
+ // warning "Cannot declare a let variable twice"
33
+ // (although, i think safari is kind of right)
34
+ safari10: true,
35
+ },
36
+ // :rs: for profiling in devtools
37
+ keep_classnames: withProfiling,
38
+ keep_fnames: withProfiling,
39
+ output: {
40
+ ecma: 5,
41
+ comments: false,
42
+ // :rs: emoji and regex not minified properly using default
43
+ // https://github.com/facebook/create-react-app/issues/2488
44
+ ascii_only: true,
45
+ },
46
+ }
47
+ }
@@ -0,0 +1,25 @@
1
+ const { existsSync, writeFileSync } = require('fs')
2
+ const path = require('path')
3
+ const packageJson = require('../package.json')
4
+
5
+ const now = new Date().toISOString()
6
+ const sitemapPath = path.resolve(__dirname, '../src/public/sitemap.xml')
7
+ const baseUrl = packageJson.url || 'https://www.createapplicationtemplate.com/'
8
+
9
+ if (existsSync(sitemapPath)) {
10
+ console.info('📝 overwriting existing sitemap.xml')
11
+ }
12
+
13
+ const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
14
+ <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
15
+ <url>
16
+ <loc>${baseUrl}</loc>
17
+ <lastmod>${now}</lastmod>
18
+ <changefreq>weekly</changefreq>
19
+ <priority>1.0</priority>
20
+ </url>
21
+ </urlset>`
22
+
23
+ writeFileSync(sitemapPath, sitemap.trim())
24
+
25
+ console.info('✅ sitemap.xml updated with lastmod:', now)