@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.
- package/.babelrc +14 -0
- package/.browserslistrc +3 -0
- package/.codex +0 -0
- package/.eslintrc.js +309 -0
- package/.husky/pre-commit +5 -0
- package/.stylelintrc.js +29 -0
- package/LICENSE +21 -0
- package/README.md +141 -0
- package/bin/create-application-template-rs.js +116 -0
- package/jest/cssTransform.js +13 -0
- package/jest/fontTransform.js +12 -0
- package/jest/setup.js +5 -0
- package/jest/setupTests.js +15 -0
- package/jest/svgTransform.js +12 -0
- package/jest.config.js +58 -0
- package/package.json +117 -0
- package/rspack/rspack.common.js +212 -0
- package/rspack/rspack.config.js +14 -0
- package/rspack/rspack.dev.js +36 -0
- package/rspack/rspack.prod.js +43 -0
- package/rspack/utilities/createEnvironmentHash.js +8 -0
- package/rspack/utilities/env.js +8 -0
- package/rspack/utilities/generateAssetManifest.js +16 -0
- package/rspack/utilities/getPaths.js +57 -0
- package/rspack/utilities/getTerserOptions.js +47 -0
- package/scripts/generate-sitemap.ts +25 -0
- package/src/app.d.ts +7 -0
- package/src/assets/favicon.ico +0 -0
- package/src/assets/logo.svg +15 -0
- package/src/components/App.spec.tsx +24 -0
- package/src/components/App.tsx +66 -0
- package/src/components/Counter.spec.tsx +38 -0
- package/src/components/Counter.tsx +26 -0
- package/src/components/Typewriter.spec.tsx +36 -0
- package/src/components/Typewriter.tsx +66 -0
- package/src/components/__snapshots__/App.spec.tsx.snap +56 -0
- package/src/components/__snapshots__/Counter.spec.tsx.snap +44 -0
- package/src/components/__snapshots__/Typewriter.spec.tsx.snap +56 -0
- package/src/fonts/Exo2-Regular.woff2 +0 -0
- package/src/fonts/Orbitron-Regular.woff2 +0 -0
- package/src/index.html +18 -0
- package/src/index.tsx +12 -0
- package/src/public/robots.txt +6 -0
- package/src/styles/App.styled.ts +42 -0
- package/src/styles/Counter.styled.ts +30 -0
- package/src/styles/Global.ts +18 -0
- package/src/styles/Logo.styled.ts +24 -0
- package/src/styles/Typewriter.styled.ts +5 -0
- package/src/styles/env.css +11 -0
- package/src/styles/theme.ts +21 -0
- 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
|
+
})
|
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,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)
|