├── .editorconfig
├── .gitignore
├── LICENSE
├── README.md
├── babel-defines.js
├── babel.config.js
├── jsconfig.json
├── package.json
├── prettier.config.js
├── public
├── about.html
└── index.html
├── src
├── app
│ ├── index.scss
│ ├── index.ts
│ └── styles
│ │ ├── body.scss
│ │ └── index.scss
├── index.ts
└── shared
│ ├── img
│ ├── .gitkeep
│ └── webpack.svg
│ └── misc
│ ├── favicon.ico
│ ├── robots.txt
│ └── sitemap.xml
├── tsconfig.json
├── webpack
├── webpack-defines.js
├── webpack-pages.js
├── webpack.common.js
├── webpack.dev.js
└── webpack.prod.js
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 |
3 | # STANDART mode
4 | # From: https://github.com/airbnb/javascript/blob/master/.editorconfig
5 |
6 | root = true
7 |
8 | [*]
9 | indent_style = space
10 | indent_size = 2
11 | charset = utf-8
12 | trim_trailing_whitespace = true
13 | insert_final_newline = true
14 | end_of_line = lf
15 | # editorconfig-tools is unable to ignore longs strings or urls
16 | max_line_length = off
17 |
18 | [CHANGELOG.md]
19 | indent_size = false
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Default
2 | .gulp
3 | .idea
4 | .vscode
5 |
6 | # Node
7 | node_modules
8 |
9 | # Dist & tests
10 | test
11 | dist
12 |
13 | # Logs:
14 | *.log
15 | npm-debug.log*
16 | yarn-debug.log*
17 | yarn-error.log*
18 |
19 | # Special
20 | Thumbs.db
21 | Desktop.ini
22 | .DS_Store*
23 | ehthumbs.db
24 | Icon?
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Evgenii Vedegis
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Webpack work template
4 |
5 | Webpack is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset.
6 |
7 |
Author: Vedees | Youtube guide (ru)
8 |
9 |
10 | ## Features:
11 |
12 | - separated configs for `dev` and `prod`
13 | - `typescript / javascript` full support
14 | - `sass / css` full support
15 | - full babel & postcss setup
16 | - 0 dependencies
17 | - the best optimization for your production
18 | - easy webpack and babel customization
19 |
20 | Everybody knows that developing runs on coffee! Thanks for your support!
21 |
22 | [![Buy me a coffee][buymeacoffee-shield]][buymeacoffee]
23 |
24 | ## Build Setup:
25 |
26 | ```bash
27 | # Download repository:
28 | git clone https://github.com/vedees/webpack-template webpack-template
29 |
30 | # Go to the app:
31 | cd webpack-template
32 |
33 | # Install dependencies:
34 | # npm install
35 | # or:
36 | yarn
37 |
38 | # Server with hot reload at http://localhost:8084/
39 | # npm run start
40 | # or:
41 | yarn start
42 |
43 | # Output will be at dist/ folder
44 | # npm run build
45 | # or:
46 | yarn build
47 | ```
48 |
49 | ## Project Structure:
50 |
51 | - `public/*.html` - HTML files
52 | - `src/app` - core app
53 | - `src/shared` - shared files
54 | - `src/shared/img` - images folder (! for html calls use correct path: `static/img/some.jpg`)
55 | - `src/shared/misc` - misc files (i.g. favicon, sitemap, etc.)
56 | - `src/index.ts` - main app entity
57 |
58 | Configs:
59 |
60 | - `/babel-defines.js` - config for babel
61 | - `/webpack/webpack-pages.js` - config for html pages
62 | - `/webpack/webpack-defines.js` - config for entire webpack
63 |
64 | Main entry point:
65 |
66 | - `src/app/index.ts` - core entry point
67 |
68 | ## Defines:
69 |
70 | Core webpack config from `/webpack/webpack-defines.js`:
71 |
72 | ```js
73 | const PATHS = {
74 | // path to the src dir
75 | src: path.join(__dirname, '../src'),
76 | // path to the output dir
77 | dist: path.join(__dirname, '../dist'),
78 | // path to the public files (html files)
79 | public: path.join(__dirname, '../public'),
80 |
81 | // path to output sub dir (js, css, fonts, etc.)
82 | assets: 'assets/',
83 | // path to output sub dir (img, icons, etc.)
84 | static: 'static/'
85 | }
86 | ```
87 |
88 | ## Pages config:
89 |
90 | Pages config from `/webpack/webpack-pages.js`:
91 |
92 | ```js
93 | const pages = [
94 | {
95 | // page title
96 | title: 'Home page',
97 | // template name `public/index.html`
98 | template: 'index.html',
99 | // output filename `dist/index.html`
100 | filename: 'index.html',
101 |
102 | // other options can be here
103 | },
104 | {
105 | title: 'About page',
106 | template: 'about.html',
107 | filename: 'about.html',
108 | }
109 | ]
110 | ```
111 |
112 | You can pass a hash of configuration options to html-webpack-plugin.
113 |
114 | Allowed values are as follows: https://github.com/jantimon/html-webpack-plugin#options
115 |
116 | ## Manual pages setup:
117 |
118 | In case if you don't want to use Pages config:
119 |
120 | 1. Create another html file in `./public`
121 | 2. Go to `./webpack/webpack.common.js`
122 | 3. Add new page to the config:
123 |
124 | ```js
125 | // index page:
126 | new HtmlWebpackPlugin({
127 | title: 'Home page',
128 | favicon: defines.src + '/shared/misc/favicon.ico',
129 | template: defines.public + '/index.html', // public/index.html page
130 | filename: 'index.html' // output file
131 | }),
132 | // about page:
133 | new HtmlWebpackPlugin({
134 | title: 'About page',
135 | favicon: defines.src + '/shared/misc/favicon.ico',
136 | template: defines.public + '/about.html', // public/about.html page
137 | filename: 'about.html' // output file
138 | }),
139 | ```
140 |
141 | ## Import libs example:
142 |
143 | Install it:
144 |
145 | ```bash
146 | yarn add bootstrap react react-dom
147 | ```
148 |
149 | Import libs to `src/app/index.ts`:
150 |
151 | ```js
152 | // React example
153 | import React from 'react'
154 |
155 | // Bootstrap example (with custom js imports)
156 | import Bootstrap from 'bootstrap/dist/js/bootstrap.min.js'
157 | import 'bootstrap/dist/js/bootstrap.min.js'
158 | ```
159 |
160 | ## Import SASS / CSS libs example:
161 |
162 | Import libs to `src/app/index.scss`:
163 |
164 | ```scss
165 | // sass lib import example:
166 | @import '../../node_modules/spinners/stylesheets/spinners';
167 | // css lib import example:
168 | @import '../../node_modules/flickity/dist/flickity.css';
169 | ```
170 |
171 | ## React example:
172 |
173 | Here's an example with React + i18n Provider.
174 |
175 | Install react:
176 |
177 | ```bash
178 | yarn add react react-dom
179 | ```
180 |
181 | Create div with id `app` in `public/index.html`:
182 |
183 | ```html
184 |
185 | ```
186 |
187 | Init the app in `src/app/index.ts`:
188 |
189 | ```tsx
190 | import React from 'react'
191 | import { createRoot } from 'react-dom/client'
192 |
193 | // app styles
194 | import './index.scss'
195 |
196 | // local providers:
197 | import { I18nProvider } from './providers/I18nProvider'
198 |
199 | const container = document.getElementById('app') as HTMLElement
200 | const root = createRoot(container)
201 |
202 | root.render(
203 |
204 | ...
205 |
206 | )
207 | ```
208 |
209 | File `src/app/providers/I18nProvider.tsx`:
210 |
211 | ```tsx
212 | import React, { FC, PropsWithChildren } from 'react'
213 |
214 | export const I18nProvider: FC = ({ children }) => {
215 | // ...
216 |
217 | return {children}
218 | }
219 | ```
220 |
221 | ## Vue example:
222 |
223 | Install vue:
224 |
225 | ```bash
226 | yarn add vue
227 | ```
228 |
229 | Init the app in `src/app/index.ts`:
230 |
231 | ```js
232 | // vue example (react one is above):
233 | const app = new Vue({
234 | el: '#app'
235 | })
236 | ```
237 |
238 | Create div with id `app` in `public/index.html`:
239 |
240 | ```html
241 |
242 | ```
243 |
244 | ### Adding Vue Components:
245 |
246 | Create your component in `src/app/components/`.
247 |
248 | **HTML Usage (in `*.html` files):**
249 |
250 | Init component in `src/app/index.ts`:
251 |
252 | ```js
253 | Vue.component('example-component', require('./components/Example.vue').default)
254 | ```
255 |
256 | In any html files:
257 |
258 | ```html
259 |
260 | ```
261 |
262 | **VUE Usage (in `*.vue` files):**
263 |
264 | Import component:
265 |
266 | ```js
267 | import ExampleComponent from '@/components/Example.vue'
268 | ```
269 |
270 | Init component (template):
271 |
272 | ```js
273 |
274 | ```
275 |
276 | Register component (script):
277 |
278 | ```js
279 | components: {
280 | Example: ExampleComponent
281 | }
282 | ```
283 |
284 | ## Adding Google Fonts:
285 |
286 | Connect fonts to `public/index.html`:
287 |
288 | ```html
289 |
290 |
291 |
292 | ```
293 |
294 | Change the font in `src/app/styles/body.scss`:
295 |
296 | ```scss
297 | html {
298 | font-family: 'Open Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, 'Apple Color Emoji', Arial, sans-serif, 'Segoe UI Emoji', 'Segoe UI Symbol' !important;
299 | }
300 | ```
301 |
302 | ## Adding local fonts:
303 |
304 | In case if you don't want to use Google Fonts:
305 |
306 | - Download fonts
307 | - Add fonts to the (i.g. `/src/shared/fonts/OpenSans/...`).
308 |
309 | Then add `@font-face` in some `.scss` file (i.g. `/src/app/styles/font.scss`):
310 |
311 | ```scss
312 | // Open Sans example:
313 | @font-face {
314 | font-family: 'Open Sans';
315 | font-style: normal;
316 | font-weight: 400;
317 | font-stretch: 100%;
318 | font-display: swap;
319 | src: url('/static/fonts/OpenSans/Open-Sans.woff2') format('woff2');
320 | unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
321 | }
322 | ```
323 |
324 | The last step is to copy these fonts into the `/dist` folder every time you build the project.
325 |
326 | Add another config for `CopyWebpackPlugin` to `/webpack/webpack.common.js`:
327 |
328 | ```js
329 | new CopyWebpackPlugin({
330 | // ...
331 |
332 | // `shared/fonts` to `dist/static/fonts`
333 | {
334 | from: `${defines.src}/shared/fonts`,
335 | to: `${defines.dist}/${defines.static}/fonts`
336 | },
337 | })
338 | ```
339 |
340 | Change the font in `src/app/styles/body.scss`:
341 |
342 | ```scss
343 | html {
344 | font-family: 'Open Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, 'Apple Color Emoji', Arial, sans-serif, 'Segoe UI Emoji', 'Segoe UI Symbol' !important;
345 | }
346 | ```
347 |
348 | ## License:
349 |
350 | [MIT](./LICENSE)
351 |
352 | Copyright (c) 2018-present, [Evgenii Vedegis](https://github.com/vedees)
353 |
354 | [buymeacoffee-shield]: https://www.buymeacoffee.com/assets/img/guidelines/download-assets-sm-2.svg
355 | [buymeacoffee]: https://www.buymeacoffee.com/vedegis
356 |
--------------------------------------------------------------------------------
/babel-defines.js:
--------------------------------------------------------------------------------
1 | const shared = {
2 | __DEV__: "process.env.NODE_ENV !== 'production'",
3 | }
4 |
5 | module.exports = {
6 | development: shared,
7 | test: shared,
8 | production: {
9 | ...shared,
10 | __DEV__: 'false',
11 | 'process.env.NODE_ENV': "'production'",
12 | },
13 | }
14 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | const defines = require('./babel-defines')
2 |
3 | function replacementPlugin(env) {
4 | return ['babel-plugin-transform-replace-expressions', { replace: defines[env] }]
5 | }
6 |
7 | const sharedPlugins = [
8 | 'preval',
9 |
10 | // install others if you need:
11 | // 'add-react-displayname',
12 | // 'babel-plugin-styled-components',
13 | // '@babel/plugin-proposal-nullish-coalescing-operator',
14 | // '@babel/plugin-proposal-optional-chaining',
15 |
16 | [
17 | 'module-resolver',
18 | {
19 | root: ['./'],
20 | extensions: ['ts', 'tsx', '.js', '.jsx', '.json', '.svg', '.png', '.jpg', '.jpeg'],
21 | alias: {
22 | '@': './src/'
23 | }
24 | }
25 | ]
26 | ]
27 |
28 | function makePresets(moduleValue) {
29 | return ['@babel/preset-env', '@babel/preset-typescript', ['@babel/preset-react', { modules: moduleValue }]]
30 | }
31 |
32 | module.exports = {
33 | env: {
34 | development: {
35 | presets: makePresets(process.env.BABEL_MODULE || false),
36 | plugins: [
37 | ...(process.env.BABEL_MODULE === 'commonjs'
38 | ? ['@babel/plugin-transform-modules-commonjs']
39 | : process.env.STORYBOOK
40 | ? []
41 | : [
42 | 'transform-commonjs' // theme-preval is commonjs and needs to be transformed to esm
43 | ]),
44 | ...sharedPlugins,
45 | replacementPlugin('development')
46 | ]
47 | },
48 | production: {
49 | presets: makePresets(false),
50 | plugins: [...sharedPlugins, replacementPlugin('production')]
51 | },
52 | test: {
53 | presets: makePresets('commonjs'),
54 | plugins: [...sharedPlugins, ['@babel/plugin-transform-modules-commonjs'], replacementPlugin('test')]
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "./",
4 | "paths": {
5 | "@/*": ["./src/*"]
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webpacktemplate",
3 | "version": "1.0.0",
4 | "description": "Webpack template",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "webpack serve --config webpack/webpack.dev.js",
8 | "build": "npm run clean & NODE_ENV=production webpack --config webpack/webpack.prod.js",
9 | "clean": "rimraf dist",
10 | "format": "prettier --cache --write '**/*.{js,css,md,mdx,ts,tsx,yml}'",
11 | "format:diff": "prettier --cache --list-different '**/*.{js,css,md,mdx,ts,tsx,yml}'",
12 | "lint": "eslint '**/*.{js,ts,tsx,md,mdx}' --max-warnings=0",
13 | "lint:fix": "npm run lint -- --fix",
14 | "test": "jest",
15 | "tscheck": "tsc",
16 | "tscheck:watch": "tsc -w"
17 | },
18 | "browserslist": {
19 | "production": [
20 | ">0.5%",
21 | "last 1 year",
22 | "not dead",
23 | "not op_mini all"
24 | ],
25 | "development": [
26 | "last 1 chrome version",
27 | "last 1 firefox version",
28 | "last 1 safari version"
29 | ]
30 | },
31 | "license": "MIT",
32 | "dependencies": {},
33 | "devDependencies": {
34 | "@babel/core": "^7.23.5",
35 | "@babel/plugin-transform-modules-commonjs": "^7.23.3",
36 | "@babel/preset-env": "^7.23.5",
37 | "@babel/preset-react": "^7.23.3",
38 | "@babel/preset-typescript": "^7.23.3",
39 | "@types/node": "^20.10.2",
40 | "babel-core": "^6.26.3",
41 | "babel-loader": "^9.1.3",
42 | "babel-plugin-module-resolver": "^5.0.0",
43 | "babel-plugin-preval": "^5.1.0",
44 | "babel-plugin-transform-commonjs": "^1.1.6",
45 | "babel-plugin-transform-remove-console": "^6.9.4",
46 | "babel-plugin-transform-replace-expressions": "^0.2.0",
47 | "copy-webpack-plugin": "latest",
48 | "css-loader": "^6.8.1",
49 | "css-minimizer-webpack-plugin": "^5.0.1",
50 | "file-loader": "^6.2.0",
51 | "html-webpack-plugin": "^5.5.3",
52 | "json-minimizer-webpack-plugin": "^4.0.0",
53 | "mini-css-extract-plugin": "^2.7.6",
54 | "postcss-loader": "^7.3.3",
55 | "postcss-preset-env": "^9.3.0",
56 | "sass": "^1.69.5",
57 | "sass-loader": "^13.3.2",
58 | "terser-webpack-plugin": "^5.3.9",
59 | "webpack": "^5.89.0",
60 | "webpack-cli": "^5.1.4",
61 | "webpack-dev-server": "^4.15.1",
62 | "webpack-merge": "^5.10.0"
63 | },
64 | "author": "https://github.com/vedees",
65 | "repository": {
66 | "type": "git",
67 | "url": "git+https://github.com/vedees/webpack-template.git"
68 | },
69 | "bugs": {
70 | "url": "https://github.com/vedees/webpack-template/issues"
71 | },
72 | "keywords": [
73 | "webpack",
74 | "babel",
75 | "typescript",
76 | "scss"
77 | ]
78 | }
79 |
--------------------------------------------------------------------------------
/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | semi: false,
3 | singleQuote: true,
4 | arrowParens: 'avoid',
5 | trailingComma: 'none',
6 | endOfLine: 'auto'
7 | }
8 |
--------------------------------------------------------------------------------
/public/about.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Webpack Template
8 |
9 |
10 |
11 |
12 |
It works!
13 |
14 |
15 |
16 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Webpack Template
8 |
9 |
10 |
11 |
12 |
It works!
13 |
14 |
15 |
16 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/app/index.scss:
--------------------------------------------------------------------------------
1 | // scss entry point
2 |
3 | // here can be imports for global libs
4 |
5 | // local styles:
6 | @import './styles/index.scss';
7 |
--------------------------------------------------------------------------------
/src/app/index.ts:
--------------------------------------------------------------------------------
1 | console.log('it works!')
2 |
3 | // core app styles:
4 | import './index.scss'
5 |
6 | // here you can init react or vue
7 |
--------------------------------------------------------------------------------
/src/app/styles/body.scss:
--------------------------------------------------------------------------------
1 | *,
2 | *:before,
3 | *:after {
4 | box-sizing: border-box;
5 | }
6 |
7 | body,
8 | html {
9 | margin: 0;
10 | padding: 0;
11 | }
12 |
13 | html {
14 | scroll-behaviour: smooth;
15 | }
16 |
17 | body {
18 | position: relative;
19 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Roboto, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';
20 | font-size: 18px;
21 | fill: currentcolor;
22 | -webkit-font-smoothing: antialiased;
23 | -moz-osx-font-smoothing: grayscale;
24 | }
25 |
--------------------------------------------------------------------------------
/src/app/styles/index.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | // scss imports can be here (local files only):
4 | @import './body.scss';
5 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | // entry point
2 | // DO NOT mess this file!
3 |
4 | import './app'
5 |
--------------------------------------------------------------------------------
/src/shared/img/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vedees/webpack-template/a4b7333328726f141d09acf1e76d5b865debe113/src/shared/img/.gitkeep
--------------------------------------------------------------------------------
/src/shared/img/webpack.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/shared/misc/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vedees/webpack-template/a4b7333328726f141d09acf1e76d5b865debe113/src/shared/misc/favicon.ico
--------------------------------------------------------------------------------
/src/shared/misc/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow: /*?*
3 | Sitemap: http://localhost:8081/sitemap.xml
4 |
5 | User-agent: Goolebot
6 | Disallow: /*?*
7 |
--------------------------------------------------------------------------------
/src/shared/misc/sitemap.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | http://localhost:8081/
5 |
6 |
7 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | /*
2 | TypeScript compiler is NOT using for build!
3 |
4 | so here's only type-checking options
5 | use: `yarn tscheck` or `yarn tscheck:watch`
6 |
7 | you can set up eslint in vs-code to see live time errors without `tscheck`
8 | */
9 |
10 | {
11 | "compilerOptions": {
12 | "target": "ESNext",
13 | "module": "CommonJS",
14 | "lib": ["ESNext", "ES6", "DOM", "DOM.Iterable"],
15 | "jsx": "react",
16 | "noEmit": true,
17 | "sourceMap": true,
18 | "resolveJsonModule": true,
19 |
20 | // strict options
21 | "strict": true,
22 | "noImplicitAny": true,
23 | "strictNullChecks": true,
24 |
25 | // js
26 | "allowJs": true,
27 | "checkJs": false,
28 | "allowSyntheticDefaultImports": true,
29 |
30 | // module resolution options
31 | "moduleResolution": "node",
32 | "forceConsistentCasingInFileNames": true,
33 | "esModuleInterop": true,
34 |
35 | // paths:
36 | "baseUrl": "./",
37 | "paths": {
38 | "@/*": ["./src/*"]
39 | }
40 | },
41 |
42 | "exclude": ["scripts", "webpack", "dist", "node_modules", "**/*.spec.ts"],
43 |
44 | // ? .jsx seems useless
45 | "include": ["src/*.d.ts", "src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
46 | }
47 |
--------------------------------------------------------------------------------
/webpack/webpack-defines.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 |
3 | const dirs = {
4 | // path to the Src dir
5 | src: path.join(__dirname, '../src'),
6 | // path to the Output dir
7 | dist: path.join(__dirname, '../dist'),
8 | // path to your html files
9 | public: path.join(__dirname, '../public')
10 | }
11 |
12 | const subDirs = {
13 | // path to Output sub dir (js, css, fonts, etc.)
14 | // i.g. `dist/assets/css/` & dist/assets/js/
15 | assets: 'assets/',
16 |
17 | // path to Output sub dir (img, icons, etc.)
18 | // i.g. `dist/static/img/` & `dist/static/fonts/`
19 | static: 'static/'
20 | }
21 |
22 | module.exports = {
23 | ...dirs,
24 | ...subDirs
25 | }
26 |
--------------------------------------------------------------------------------
/webpack/webpack-pages.js:
--------------------------------------------------------------------------------
1 | // automation for `HtmlWebpackPlugin`
2 |
3 | // Notes:
4 | // - remember to restart server after new page added
5 | // - link on the html must be with .html suffix (i.g. About )
6 |
7 | const pages = [
8 | {
9 | // page title
10 | title: 'Home page',
11 | // template name `public/index.html`
12 | template: 'index.html',
13 | // output filename `dist/index.html`
14 | filename: 'index.html'
15 |
16 | // you can pass a hash of configuration options to html-webpack-plugin.
17 | // Allowed values are as follows:
18 | // read more: https://github.com/jantimon/html-webpack-plugin#options
19 | },
20 | {
21 | title: 'About page',
22 | template: 'about.html',
23 | filename: 'about.html'
24 | }
25 | ]
26 |
27 | module.exports = pages
28 |
--------------------------------------------------------------------------------
/webpack/webpack.common.js:
--------------------------------------------------------------------------------
1 | /* Base config:
2 | ========================================================================== */
3 |
4 | //
5 | const defines = require('./webpack-defines')
6 | const pages = require('./webpack-pages')
7 |
8 | // copy files from dev (i.g. `assets/img/*`) to dist (i.g `static/img/*`)
9 | const CopyWebpackPlugin = require('copy-webpack-plugin')
10 | // extract css from js to another files
11 | const MiniCssExtractPlugin = require('mini-css-extract-plugin')
12 | // html support
13 | const HtmlWebpackPlugin = require('html-webpack-plugin')
14 |
15 | // helpers:
16 | // I want one rule for development and production, so I use `isDev` to check the process
17 | const isDev = process.env.NODE_ENV !== 'production'
18 |
19 | module.exports = {
20 | entry: {
21 | app: `${defines.src}/index.ts`
22 | // another app example:
23 | // auth: `${defines.src}/_auth/index.ts`
24 | },
25 | output: {
26 | path: defines.dist,
27 | // if you need hash:
28 | // filename: `${defines.assets}js/[name].[contenthash].js`
29 | // if you don't need hash:
30 | filename: `${defines.assets}js/[name].js`
31 | },
32 |
33 | // optimization (chunks)
34 | optimization: {
35 | chunkIds: 'named',
36 | mergeDuplicateChunks: true,
37 |
38 | splitChunks: {
39 | chunks: 'async',
40 | minSize: 20000,
41 | minRemainingSize: 0,
42 | minChunks: 1,
43 | maxAsyncRequests: 30,
44 | maxInitialRequests: 30,
45 | enforceSizeThreshold: 50000,
46 | cacheGroups: {
47 | defaultVendors: {
48 | name: 'vendors', // or comment name to make chunks works
49 | chunks: 'all',
50 | // the way to keep kit in the vendors
51 | test: /[\\/]node_modules[\\/]|[\\/]ui-kit[\\/]/,
52 | priority: -10,
53 | reuseExistingChunk: true
54 | },
55 | default: {
56 | minChunks: 2,
57 | priority: -20,
58 | reuseExistingChunk: true
59 | }
60 | }
61 | }
62 | },
63 |
64 | module: {
65 | rules: [
66 | // js(x) & ts(x)
67 | {
68 | test: /\.(ts|js)x?$/,
69 | exclude: /node_modules/,
70 | use: {
71 | loader: 'babel-loader',
72 |
73 | options: {
74 | // react-refresh example:
75 | // plugins: [isDev && require.resolve('react-refresh/babel')].filter(Boolean)
76 | }
77 | }
78 | },
79 |
80 | // sass & css
81 | {
82 | test: /\.s(a|c)ss$/,
83 | use: [
84 | MiniCssExtractPlugin.loader,
85 | 'css-loader',
86 | {
87 | loader: 'postcss-loader',
88 | options: {
89 | postcssOptions: {
90 | plugins: [
91 | [
92 | // add more postcss plugins here
93 | // ...
94 |
95 | // https://www.npmjs.com/package/postcss-preset-env
96 | // it's including autoprefixer by default (config is in `package.json`)
97 | // pass `autoprefixer: false` to disable autoprefixer
98 | 'postcss-preset-env'
99 | ]
100 | ],
101 | postcssOptions: {
102 | parser: 'postcss-js'
103 | },
104 | execute: true
105 | }
106 | }
107 | },
108 | {
109 | loader: 'sass-loader',
110 | options: {
111 | sourceMap: isDev
112 | }
113 | }
114 | ]
115 | },
116 |
117 | // svg in js(x) & ts(x)
118 | {
119 | test: /\.svg$/i,
120 | issuer: /\.[jt]sx?$/,
121 | use: [
122 | // https://react-svgr.com/docs/webpack/
123 | '@svgr/webpack'
124 | ]
125 | },
126 |
127 | // fonts
128 | {
129 | test: /\.(woff(2)?|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/,
130 | loader: 'file-loader',
131 | options: {
132 | name: '[name].[ext]'
133 | }
134 | },
135 |
136 | // images
137 | {
138 | test: /\.(?:ico|gif|png|jpg|jpeg)$/i,
139 | type: 'asset/resource'
140 | }
141 | ]
142 | },
143 | plugins: [
144 | // html pages:
145 |
146 | // can be manually (one by one):
147 | // new HtmlWebpackPlugin({
148 | // title: 'Home page',
149 | // favicon: defines.src + '/shared/misc/favicon.ico',
150 | // template: defines.public + '/index.html',
151 | // filename: 'index.html' // output file
152 | // }),
153 | // new HtmlWebpackPlugin({
154 | // title: 'About page',
155 | // favicon: defines.src + '/shared/misc/favicon.ico',
156 | // template: defines.public + '/about.html',
157 | // filename: 'about.html' // output file
158 | // }),
159 |
160 | // or by config (from `webpack-pages.js`):
161 | ...pages.map(
162 | page =>
163 | new HtmlWebpackPlugin({
164 | title: page.title,
165 | template: defines.public + '/' + page.template,
166 | filename: page.filename,
167 | // default:
168 | favicon: defines.src + '/shared/misc/favicon.ico'
169 | })
170 | ),
171 |
172 | // extract css from js / ts files (it's a basic setup to keep css in `css` folder)
173 | // https://webpack.js.org/plugins/mini-css-extract-plugin/
174 | new MiniCssExtractPlugin({
175 | // if you need hash:
176 | // filename: `${defines.assets}css/[name].[contenthash].css`,
177 | // if you don't need hash:
178 | filename: `${defines.assets}css/[name].css`,
179 | chunkFilename: '[id].css'
180 | }),
181 |
182 | // copy files from target to destination folder
183 | new CopyWebpackPlugin({
184 | patterns: [
185 | // `shared/img` to `dist/static/img`
186 | {
187 | from: `${defines.src}/shared/img`,
188 | to: `${defines.dist}/${defines.static}/img`
189 | },
190 |
191 | // others:
192 | // `shared/fonts` to `dist/static/fonts`
193 | // {
194 | // from: `${defines.src}/shared/fonts`,
195 | // to: `${defines.dist}/${defines.static}/fonts`
196 | // },
197 |
198 | // misc
199 | // `shared/misc` to `dist/`
200 | {
201 | from: `${defines.src}/shared/misc`,
202 | to: `${defines.dist}`
203 | }
204 | ]
205 | })
206 | ],
207 |
208 | resolve: {
209 | alias: {
210 | // no need since I use `tsconfig` & `jsconfig`
211 | // '@': defines.src
212 | },
213 | extensions: ['.ts', '.tsx', '.js', '.jsx']
214 | }
215 | }
216 |
--------------------------------------------------------------------------------
/webpack/webpack.dev.js:
--------------------------------------------------------------------------------
1 | /* Development build:
2 | ========================================================================== */
3 | const { merge } = require('webpack-merge')
4 |
5 | // default config
6 | const commonConfig = require('./webpack.common.js')
7 |
8 | module.exports = merge(commonConfig, {
9 | mode: 'development',
10 | devtool: 'inline-source-map',
11 |
12 | // spin up a server for quick development
13 | devServer: {
14 | compress: true,
15 | open: false,
16 | hot: true,
17 | port: 8084,
18 | client: {
19 | progress: false,
20 | overlay: {
21 | errors: false,
22 | warnings: false
23 | }
24 | },
25 | // to test in other devices:
26 | // allowedHosts: 'all',
27 |
28 | // fix CORS:
29 | historyApiFallback: true
30 | },
31 | plugins: [
32 | // react refresh example:
33 | // https://github.com/pmmmwh/react-refresh-webpack-plugin
34 | // new ReactRefreshWebpackPlugin()
35 | ],
36 | resolve: {
37 | extensions: ['.ts', '.tsx', '.js', '.jsx']
38 | },
39 | watchOptions: {
40 | // for some systems, watching many files can result in a lot of CPU or memory usage
41 | // https://webpack.js.org/configuration/watch/#watchoptionsignored
42 | // ! don't use this pattern, if you have a monorepo with linked packages
43 | ignored: /node_modules/
44 | }
45 | })
46 |
--------------------------------------------------------------------------------
/webpack/webpack.prod.js:
--------------------------------------------------------------------------------
1 | /* Production build:
2 | ========================================================================== */
3 | const { merge } = require('webpack-merge')
4 | const defines = require('./webpack-defines')
5 |
6 | // plugins for production build only:
7 | const JsonMinimizerPlugin = require('json-minimizer-webpack-plugin')
8 | const TerserPlugin = require('terser-webpack-plugin')
9 | const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
10 |
11 | // default config
12 | const commonConfig = require('./webpack.common.js')
13 |
14 | module.exports = merge(commonConfig, {
15 | mode: 'production',
16 | devtool: false,
17 | output: {
18 | path: defines.dist
19 | },
20 | plugins: [
21 | // compress example:
22 | // new CompressionPlugin({
23 | // exclude: /\/static/,
24 | // }),
25 | ],
26 | module: {
27 | rules: []
28 | },
29 | performance: {
30 | hints: false,
31 | maxEntrypointSize: 512000,
32 | maxAssetSize: 512000
33 | },
34 | optimization: {
35 | minimize: true,
36 | minimizer: [
37 | new JsonMinimizerPlugin(),
38 | new TerserPlugin(),
39 | new CssMinimizerPlugin({
40 | minimizerOptions: {
41 | // no ie please!
42 | // targets: { ie: 11 },
43 | preset: [
44 | 'default',
45 | {
46 | discardComments: { removeAll: true }
47 | }
48 | ]
49 | }
50 | })
51 | ]
52 | }
53 | })
54 |
--------------------------------------------------------------------------------