Skip to content

Commit b38ab5e

Browse files
committed
add image optimization, almost complete README
1 parent a5fbab5 commit b38ab5e

File tree

17 files changed

+902
-41
lines changed

17 files changed

+902
-41
lines changed

README.md

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,25 +32,74 @@ npm run dev
3232
- **shared**
3333
- **Header**
3434
- **Layout**
35+
- **static**
36+
- **images**
37+
- **scripts**
38+
- **styles**
3539
- **types**
3640

3741
## How it works
3842

39-
`./src` contains `App.tsx`, which is the entry point of the React app. It imports components from `./src/shared` and global styles from `./assets/styles/`. `App.tsx` is in turn imported be server and client files in `./src/server/` and `./src/client/`, respectively.
43+
The `./dist/` folder is the root of the site. It is created by Webpack and contains the result of the build process:
44+
45+
```shell
46+
npm run dev
47+
```
48+
49+
or
50+
51+
```shell
52+
npm run build
53+
```
54+
55+
`./src` contains `App.tsx`, which is the entry point of the React app. It imports components from `./src/shared` and global styles from `./assets/styles/`. `App.tsx` is in turn imported by server (`server.tsx`) and client (`index.tsx`) files in `./src/server/` and `./src/client/`, respectively.
56+
57+
The `app.get()` method in server code (`./src/server/server.tsx`) specifies a callback function that will render to string React component from `App.tsx` and past it in a HTML template (`./src/server/indexTemplate.ts`), whenever there is an HTTP GET request with a path (`/`) relative to the site root.
4058

41-
The `app.get()` method specifies a callback function that will render to string React component from `App.tsx` and past it in a HTML template, whenever there is an HTTP GET request with a path ('/') relative to the site root. HTML template are in `./src/server`.
59+
After the `load` event is fired, the client code `hydrate` obtained React root.
4260

43-
After the `load` event is fired, the client code `hydrate` obtained React component.
61+
All files in `./src/static/` are copied to the `./dist/client` folder without changes. For example, the `./src/static/images` folder will be copied to `./dist/client/images`. All files in `./src/static` are accessible through the virtual prefix `/static`. For example, the `./src/static/images/raster/favicon/favicon.png` file will be available at the address `http://localhost:3000/static/images/raster/favicon/favicon.png` === `/static/images/raster/favicon/favicon.png`.
62+
63+
Images in `./src/static/images` are optimized by Webpack. For images with `jpeg` or `jpg` or `png` extentions, the `image-minimizer-webpack-plugin` and `sharp` generate a WebP version of the images.
64+
65+
After each re-building webpack plugin `fork-ts-checker-webpack-plugin` checks the typescript code for errors.
66+
67+
The `browserslist` is used by babel and postcss to compile code for the specified browsers. The list of browsers is specified in the `package.json` file.
4468

4569
## What is used in the template?
4670

71+
### Code
72+
73+
- Webpack loader (babel-loader)
74+
- Webpack plugin (fork-ts-checker-webpack-plugin)
75+
- browserslist
76+
77+
### Styles
78+
79+
- Stylus
80+
- postcss
81+
- Webpack loaders (stylus-loader, css-loader, postcss-loader, style-loader)
82+
- browserslist
83+
84+
### Prettier && Linter
85+
86+
- Prettier
87+
- ESLint
88+
4789
### Hot Module Replacement
4890

49-
- express server
91+
- Express server
5092
- react-refresh-webpack-plugin
5193
- React Fast Refresh
52-
- Webpack modules and plugins (webpack-dev-middleware, webpack-hot-middleware, webpack.HotModuleReplacementPlugin)
94+
- Webpack modules and plugins (webpack-dev-middleware, webpack-hot-middleware)
95+
- Webpack plugins (webpack.HotModuleReplacementPlugin)
5396

5497
### Server-Side Rendering
5598

56-
- express server
99+
- Express server
100+
- Nodemon
101+
102+
### Image Optimization
103+
104+
- Webpack plugin (image-minimizer-webpack-plugin)
105+
- Sharp

bin/dev.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ hmrServer.use(
3737
hmrServer.use(
3838
webpackDevMiddleware(clientCompiler, {
3939
publicPath: webpackClientConfig.output.publicPath,
40-
serverSideRender: true,
4140
writeToDisk: true,
4241
stats: 'errors-only',
4342
})
@@ -50,20 +49,21 @@ hmrServer.use(
5049
);
5150

5251
hmrServer.listen(3001, () => {
53-
console.log('HMR Server successfully started');
52+
console.log('\nHMR Server successfully started on http://localhost:3001\n');
5453
});
5554

5655
const serverCompiler = webpack(webpackServerConfig);
5756

5857
serverCompiler.run((err) => {
5958
if (err) {
60-
console.log(`Compilation failed:`, err);
59+
console.log(`\nCompilation with server config was failed: ${err}\n`);
6160
}
61+
6262
serverCompiler.watch({}, (err) => {
6363
if (err) {
64-
console.log(`Compilation failed:`, err);
64+
console.log(`\nCompilation with server config was failed: ${err}\n`);
6565
}
66-
console.log('Compilation was successfully');
66+
console.log('\nCompilation with server config was successful\n');
6767
});
6868

6969
nodemon({
@@ -75,6 +75,6 @@ serverCompiler.run((err) => {
7575
});
7676

7777
console.log(
78-
'\n!!!Server!!!\nServer started on port http://localhost:3000\n!!!Server!!!\n'
78+
'\n!!!Server!!!\nServer started on port http://localhost:3000\n!!!Server!!!'
7979
);
8080
});

config/webpack.client.config.js

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,70 @@
11
/* eslint-disable no-undef */
22
const path = require('path');
3-
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
43
const webpack = require('webpack');
4+
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
5+
const CopyPlugin = require('copy-webpack-plugin');
6+
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin');
57
const ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
68
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
79

810
const { NODE_ENV } = process.env;
911
const MODULE_CODE_REGEXP = /\.[tj]sx?$/;
1012
const MODULE_STYLES_REGEXP = /\.module\.styl$/;
1113
const GLOBAL_STYLES_REGEXP = /\.global\.styl$/;
14+
const ALL_IMAGES_REGEXP = /\.(png|svg|jpe?g|gif|ico)$/i;
15+
const TOWEBP_IMAGES_REGEXP = /\.(jpe?g|png)$/i;
16+
17+
const basePlugins = [
18+
new CopyPlugin({
19+
patterns: [{ from: path.resolve(__dirname, '../src/static') }],
20+
}),
21+
new ImageMinimizerPlugin({
22+
deleteOriginalAssets: false,
23+
test: TOWEBP_IMAGES_REGEXP,
24+
minimizer: {
25+
implementation: ImageMinimizerPlugin.sharpMinify,
26+
options: {
27+
encodeOptions: {
28+
jpeg: {
29+
quality: 75,
30+
effort: 9,
31+
},
32+
png: {
33+
quality: 75,
34+
effort: 9,
35+
},
36+
},
37+
},
38+
},
39+
generator: [
40+
{
41+
type: 'import',
42+
preset: 'webp',
43+
implementation: ImageMinimizerPlugin.sharpGenerate,
44+
options: {
45+
encodeOptions: {
46+
webp: {
47+
quality: 80,
48+
effort: 6,
49+
},
50+
},
51+
},
52+
},
53+
{
54+
type: 'asset',
55+
implementation: ImageMinimizerPlugin.sharpGenerate,
56+
options: {
57+
encodeOptions: {
58+
webp: {
59+
quality: 80,
60+
effort: 6,
61+
},
62+
},
63+
},
64+
},
65+
],
66+
}),
67+
];
1268

1369
module.exports = {
1470
entry: [
@@ -18,7 +74,7 @@ module.exports = {
1874
output: {
1975
path: path.resolve(__dirname, '../dist/client'),
2076
filename: 'client.js',
21-
publicPath: '//localhost:3001/static',
77+
publicPath: 'http://localhost:3001/static',
2278
},
2379

2480
module: {
@@ -65,6 +121,16 @@ module.exports = {
65121
{
66122
test: GLOBAL_STYLES_REGEXP,
67123
use: [
124+
{
125+
loader: 'style-loader',
126+
},
127+
{
128+
loader: 'string-replace-loader',
129+
options: {
130+
search: /@supports\s\(selector:\sfocus-visible\)/g,
131+
replace: '@supports selector(:focus-visible)',
132+
},
133+
},
68134
{
69135
loader: 'css-loader',
70136
},
@@ -76,6 +142,14 @@ module.exports = {
76142
},
77143
],
78144
},
145+
{
146+
test: ALL_IMAGES_REGEXP,
147+
include: [path.resolve(__dirname, './src/assets/images')],
148+
type: 'asset/resource',
149+
generator: {
150+
filename: '[name][ext]',
151+
},
152+
},
79153
],
80154
},
81155

@@ -89,6 +163,7 @@ module.exports = {
89163
NODE_ENV === 'development'
90164
? [
91165
new CleanWebpackPlugin(),
166+
...basePlugins,
92167
new webpack.HotModuleReplacementPlugin(),
93168
new ReactRefreshPlugin({
94169
overlay: {
@@ -97,7 +172,7 @@ module.exports = {
97172
}),
98173
new ForkTsCheckerWebpackPlugin({ typescript: { mode: 'write-dts' } }),
99174
]
100-
: [],
175+
: basePlugins,
101176

102177
mode: NODE_ENV === 'development' ? 'development' : 'production',
103178
};

config/webpack.server.config.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ const ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
66

77
const { NODE_ENV } = process.env;
88

9+
const MODULE_CODE_REGEXP = /\.[tj]sx?$/;
10+
const STYLES_REGEXP = /.styl$/;
11+
912
module.exports = {
1013
entry: path.resolve(__dirname, '../src/server/server.tsx'),
1114

@@ -17,15 +20,15 @@ module.exports = {
1720
module: {
1821
rules: [
1922
{
20-
test: /\.[tj]sx?$/,
23+
test: MODULE_CODE_REGEXP,
2124
use: [
2225
{
2326
loader: 'babel-loader',
2427
},
2528
],
2629
},
2730
{
28-
test: /\.styl$/,
31+
test: STYLES_REGEXP,
2932
use: [
3033
{
3134
loader: 'css-loader',
@@ -51,7 +54,14 @@ module.exports = {
5154

5255
plugins:
5356
NODE_ENV === 'development'
54-
? [new webpack.HotModuleReplacementPlugin(), new ReactRefreshPlugin()]
57+
? [
58+
new webpack.HotModuleReplacementPlugin(),
59+
new ReactRefreshPlugin({
60+
overlay: {
61+
sockIntegration: 'whm',
62+
},
63+
}),
64+
]
5565
: [],
5666

5767
externals: [webpackNodeExternals()],

0 commit comments

Comments
 (0)