minista 0.10.3 → 1.0.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/README.md CHANGED
@@ -14,11 +14,12 @@
14
14
 
15
15
  ## About
16
16
 
17
- minista(ミニスタ)は、React(JSX)で書ける web コーディング用の小さいスタティックサイトジェネレーターです。
17
+ minista(ミニスタ)は、React (TSX/JSX)で書けるスタティックサイトジェネレーターです。SaaS web テンプレートコーディング業務を想定し、ビルド時の納品用データが綺麗(ヒューマンリーダブル)であることを重視しています。
18
18
 
19
19
  - ゼロコンフィグで始められる
20
- - React(JSX)から静的な HTML を出力
21
- - CSS と JavaScript Minify 出力
20
+ - React (TSX/JSX)から 100%静的な HTML を出力
21
+ - CSS と JavaScript を個別に Minify 出力
22
+ - SVG スプライトアイコンを自動生成
22
23
  - Next.js 風のディレクトリ構成
23
24
 
24
25
  ## How To Use
@@ -54,16 +55,15 @@ src
54
55
  // Page Example
55
56
  //----------------------------------------------------
56
57
 
57
- import React from "react" // Required!
58
58
  import { render } from "minista" // Required!
59
59
 
60
- const Home = () => {
61
- return render( // Required!
60
+ const PageHome = () => {
61
+ return (
62
62
  <h1>Hello</h1>
63
63
  )
64
64
  }
65
65
 
66
- export default Home
66
+ export default render(PageHome) // Required!
67
67
  ```
68
68
 
69
69
  #### Develop
@@ -89,11 +89,10 @@ $ minista build
89
89
  #### Input
90
90
 
91
91
  ```js
92
- import React from "react"
93
92
  import { render, Comment } from "minista"
94
93
 
95
- const Home = () => {
96
- return render(
94
+ const PageHome = () => {
95
+ return (
97
96
  <>
98
97
  <Comment text="Comment Test" />
99
98
  <h1>Hello</h1>
@@ -101,7 +100,7 @@ const Home = () => {
101
100
  )
102
101
  }
103
102
 
104
- export default Home
103
+ export default render(PageHome)
105
104
  ```
106
105
 
107
106
  #### output
@@ -123,7 +122,131 @@ export default Home
123
122
 
124
123
  ### webpack
125
124
 
126
- プロジェクトの root に `webpack.config.js` を配置することで設定を追加できます。
125
+ プロジェクトの root に `webpack.config.js` を配置することで設定をマージできます。
126
+
127
+ ```js
128
+ //----------------------------------------------------
129
+ // Example: User > webpack.config.js
130
+ //----------------------------------------------------
131
+
132
+ // No installation required.
133
+ const MiniCssExtractPlugin = require("mini-css-extract-plugin")
134
+ const CopyPlugin = require("copy-webpack-plugin")
135
+
136
+ // Example of dev mode
137
+ const isDev = process.env.NODE_ENV !== "production"
138
+
139
+ const webpackConfig = {
140
+ // Merge
141
+ devServer: {
142
+ open: ["/index.html"],
143
+ },
144
+ plugins: [
145
+ // Replace
146
+ new MiniCssExtractPlugin({
147
+ filename: "assets/[name].css",
148
+ }),
149
+ // Replace
150
+ new CopyPlugin({
151
+ patterns: [{ from: "./static", to: "./", noErrorOnMissing: true }],
152
+ }),
153
+ ],
154
+
155
+ // All optimization is replaced.
156
+ optimization: {
157
+ minimize: !isDev,
158
+ minimizer: [
159
+ /* Replace plugins */
160
+ ],
161
+ },
162
+ }
163
+
164
+ module.exports = webpackConfig
165
+ ```
166
+
167
+ ### TypeScript
168
+
169
+ TypeScript `.tsx` でページを作成する場合はモジュールを追加し `tsconfig.json` をプロジェクトの root に配置。エントリーポイントとして `src/assets/index.ts` があれば `src/assets/index.js` の代わりに使用します。
170
+
171
+ ```bash
172
+ $ npm install --save-dev typescript @types/react @types/react-dom
173
+ ```
174
+
175
+ ```json
176
+ {
177
+ "compilerOptions": {
178
+ "target": "esnext",
179
+ "module": "esnext",
180
+ "baseUrl": ".",
181
+ "allowJs": true,
182
+ "strict": true,
183
+ "noImplicitAny": false,
184
+ "strictNullChecks": true,
185
+ "noUnusedLocals": true,
186
+ "noUnusedParameters": true,
187
+ "noImplicitReturns": true,
188
+ "moduleResolution": "node",
189
+ "esModuleInterop": true,
190
+ "isolatedModules": false,
191
+ "skipLibCheck": true,
192
+ "forceConsistentCasingInFileNames": true,
193
+ "resolveJsonModule": true,
194
+ "jsx": "react-jsx"
195
+ },
196
+ "include": ["**/*.ts", "**/*.tsx"],
197
+ "exclude": ["node_modules", "dist", "webpack.config.js"]
198
+ }
199
+ ```
200
+
201
+ ```bash
202
+ # ----------------------------------------------------
203
+ # Directory Example
204
+ # ----------------------------------------------------
205
+
206
+ public # Copy root
207
+ src
208
+ ├── assets
209
+ │ └── index.ts (or index.js) # Required!
210
+ ├── components
211
+ │ └── layout.js
212
+ └── pages # Required!
213
+ ├── about
214
+ │ └── index.tsx
215
+ └── index.tsx
216
+ ```
217
+
218
+ ### Babel
219
+
220
+ Babel はプロジェクトの root に `.babelrc` もしくは `babel.config.js` を配置することで設定を上書きできます。カスタマイズしない場合は以下の設定が適応されます。
221
+
222
+ ```js
223
+ // JavaScript
224
+ const babelJsxOptions = {
225
+ presets: [
226
+ "@babel/preset-env",
227
+ [
228
+ "@babel/preset-react",
229
+ {
230
+ runtime: "automatic",
231
+ },
232
+ ],
233
+ ],
234
+ }
235
+
236
+ // TypeScript
237
+ const babelTsxOptions = {
238
+ presets: [
239
+ "@babel/preset-env",
240
+ [
241
+ "@babel/preset-react",
242
+ {
243
+ runtime: "automatic",
244
+ },
245
+ ],
246
+ ["@babel/preset-typescript"],
247
+ ],
248
+ }
249
+ ```
127
250
 
128
251
  ### PostCSS
129
252
 
@@ -131,12 +254,12 @@ PostCSS はゼロコンフィグで以下のプラグインが適応されます
131
254
 
132
255
  ```js
133
256
  module.exports = {
134
- plugins: {
135
- "postcss-import": {},
136
- "postcss-flexbugs-fixes": {},
137
- "postcss-sort-media-queries": {},
138
- "postcss-preset-env": {},
139
- },
257
+ plugins: [
258
+ "postcss-import",
259
+ "postcss-flexbugs-fixes",
260
+ "postcss-sort-media-queries",
261
+ "postcss-preset-env",
262
+ ],
140
263
  }
141
264
  ```
142
265
 
@@ -148,18 +271,66 @@ module.exports = {
148
271
  $ npm install --save-dev sass-loader sass
149
272
  ```
150
273
 
274
+ ### Style only
275
+
276
+ プロジェクトに JavaScript が全く必要ない場合はエントリーポイントを CSS ファイルに変更します。これにより空の JavaScript ファイルを出力することなく納品用データを生成できます。
277
+
278
+ ```js
279
+ //----------------------------------------------------
280
+ // Example: User > webpack.config.js
281
+ //----------------------------------------------------
282
+
283
+ const webpackConfig = {
284
+ entry: { bundle: "./src/assets/index.css" },
285
+ }
286
+
287
+ module.exports = webpackConfig
288
+ ```
289
+
290
+ ### SVG sprite icons
291
+
292
+ `src/assets/icons` ディレクトリに SVG ファイルを置くと SVG スプライトアイコンの `dist/assets/icons.svg` が生成されます。以下のようなコンポーネントを作ることでアイコンを呼び出せます。
293
+
294
+ ```js
295
+ // Example: ./src/components/svg-sprite-icon.tsx
296
+ export interface SvgSpriteIconProps {
297
+ iconId?: string;
298
+ }
299
+
300
+ export const SvgSpriteIcon = (props: SvgSpriteIconProps) => {
301
+ const { iconId } = props
302
+ return (
303
+ <svg className="icon" role="img">
304
+ <use xlinkHref={`/assets/icons.svg#${iconId}`} />
305
+ </svg>
306
+ )
307
+ }
308
+ ```
309
+
310
+ ```html
311
+ <!-- dist html -->
312
+ <svg role="img" class="icon">
313
+ <use xlink:href="/assets/icons.svg#star"></use>
314
+ </svg>
315
+ ```
316
+
151
317
  ## Media
152
318
 
153
319
  - [React(JSX)で書けるコーディング用 SSG - minista v0](https://zenn.dev/qrac/articles/7537521afcd1bf)
154
320
 
155
321
  ## Respect
156
322
 
157
- - [Charge — an opinionated, zero-config static site generator](https://charge.js.org/)
158
323
  - [Next.js by Vercel - The React Framework](https://nextjs.org/)
324
+ - [Charge — an opinionated, zero-config static site generator](https://charge.js.org/)
325
+ - [Eleventy, a simpler static site generator.](https://www.11ty.dev/)
159
326
  - [Node Interface | webpack](https://webpack.js.org/api/node/)
327
+ - [natemoo-re/microsite](https://github.com/natemoo-re/microsite)
328
+ - [Astro](https://astro.build/)
160
329
  - [テンプレートエンジンに React を使いつつ、きれいな HTML を生成したいんじゃ!!](https://zenn.dev/otsukayuhi/articles/e52651b4e2c5ae7c4a17)
161
330
  - [EJS をやめて React で HTML を書く](https://zenn.dev/hisho/scraps/4ef6c6106a6395)
162
331
  - [MPA(マルチページアプリ)で webpack を使う](https://www.key-p.com/blog/staff/archives/107125)
332
+ - [HTML コーディングでも React+TypeScript の開発体験を得る](https://zenn.dev/nanaki14/articles/html-template-react)
333
+ - [Astro と microCMS でポートフォリオサイトを作る](https://zenn.dev/takanorip/articles/c75717c280c81d)
163
334
 
164
335
  ## License
165
336
 
package/cli.js CHANGED
@@ -1,78 +1,79 @@
1
1
  #!/usr/bin/env node
2
-
3
- //----------------------------------------------------
4
- // Global Require
5
- //----------------------------------------------------
6
-
7
2
  const fs = require("fs")
8
3
  const path = require("path")
9
4
  const glob = require("glob")
10
-
11
- //----------------------------------------------------
12
- // Variables
13
- //----------------------------------------------------
14
-
15
- const isDev = process.argv[2] !== "build"
16
- process.env.NODE_ENV = isDev ? "development" : "production"
17
-
18
- //----------------------------------------------------
19
- // webpack
20
- //----------------------------------------------------
21
-
22
5
  const webpack = require("webpack")
23
- const { merge } = require("webpack-merge")
6
+ const { mergeWithCustomize, customizeObject, unique } = require("webpack-merge")
24
7
  const webpackDevServer = require("webpack-dev-server")
25
- const HtmlWebpackPlugin = require("html-webpack-plugin")
26
-
27
- const webpackConfig = require("./webpack.config")
28
- const userWebpackConfig = fs.existsSync(path.resolve("webpack.config.js"))
29
- ? require(path.resolve("webpack.config"))
30
- : {}
31
- const mergedWebpackConfig = merge(webpackConfig, userWebpackConfig)
8
+ const beautify = require("js-beautify")
32
9
 
33
- const htmlPlugins = mergedWebpackConfig.plugins.filter(
34
- (plugin) => plugin.constructor === HtmlWebpackPlugin
35
- )
36
- const otherPlugins = mergedWebpackConfig.plugins.filter(
37
- (plugin) => plugin.constructor !== HtmlWebpackPlugin
38
- )
39
- const mergedHtmlPlugins = [
40
- ...new Map(
41
- htmlPlugins.map((plugin) => [plugin.userOptions.filename, plugin])
42
- ).values(),
43
- ]
44
- const mergedPlugins = [...mergedHtmlPlugins, ...otherPlugins]
45
- mergedWebpackConfig.plugins = mergedPlugins
10
+ function getWebpackConfig() {
11
+ return require("./webpack.config")
12
+ }
46
13
 
47
- const webpackCompiler = webpack(mergedWebpackConfig)
48
- const devServerOptions = Object.assign({}, mergedWebpackConfig.devServer)
14
+ function getUserWebpackConfig() {
15
+ if (fs.existsSync(path.resolve("webpack.config.js"))) {
16
+ return require(path.resolve("webpack.config"))
17
+ } else {
18
+ return {}
19
+ }
20
+ }
49
21
 
50
- const webpackDev = () => new webpackDevServer(webpackCompiler, devServerOptions)
22
+ function getMergedWebpackConfig({ config, userConfig }) {
23
+ const mergedConfig = mergeWithCustomize({
24
+ customizeObject: customizeObject({
25
+ optimization: "replace",
26
+ }),
27
+ customizeArray: unique(
28
+ "plugins",
29
+ ["MiniCssExtractPlugin", "CopyPlugin"],
30
+ (plugin) => plugin.constructor && plugin.constructor.name
31
+ ),
32
+ })(config, userConfig)
33
+ const filterdPlugins = filterWebpackPlugins({
34
+ plugins: mergedConfig.plugins,
35
+ })
36
+ mergedConfig.plugins = filterdPlugins
37
+ return mergedConfig
38
+ }
51
39
 
52
- const webpackBuild = () =>
53
- webpackCompiler.run((err, stats) => {
54
- err && console.log(err)
55
- stats &&
56
- console.log(
57
- stats.toString({
58
- colors: true,
59
- })
60
- )
61
- beautifyHTML()
40
+ function filterWebpackPlugins({ plugins }) {
41
+ const filterdHtmlWebpackPlugins = filterHtmlWebpackPlugins({
42
+ plugins: plugins,
43
+ })
44
+ const filteredOtherWebpackPlugins = filterOtherWebpackPlugins({
45
+ plugins: plugins,
62
46
  })
47
+ return [...filterdHtmlWebpackPlugins, ...filteredOtherWebpackPlugins]
48
+ }
63
49
 
64
- //----------------------------------------------------
65
- // Beautify
66
- //----------------------------------------------------
50
+ function filterHtmlWebpackPlugins({ plugins }) {
51
+ const htmlWebpackPlugins = plugins.filter(
52
+ (plugin) => plugin.constructor.name === "HtmlWebpackPlugin"
53
+ )
54
+ const mergedHtmlWebpackPlugins = [
55
+ ...new Map(
56
+ htmlWebpackPlugins.map((plugin) => [plugin.userOptions.filename, plugin])
57
+ ).values(),
58
+ ]
59
+ return mergedHtmlWebpackPlugins
60
+ }
67
61
 
68
- const beautify = require("js-beautify")
69
- const beautifyOptions = {
70
- indent_size: 2,
71
- max_preserve_newlines: 0,
62
+ function filterOtherWebpackPlugins({ plugins }) {
63
+ const otherPlugins = plugins.filter(
64
+ (plugin) => plugin.constructor.name !== "HtmlWebpackPlugin"
65
+ )
66
+ return otherPlugins
72
67
  }
73
68
 
74
- const beautifyHTML = () => {
75
- glob.sync("dist/**/*.html").forEach((file) => {
69
+ function beautifyHtmlFiles({
70
+ htmlFilesPath,
71
+ beautifyOptions = {
72
+ indent_size: 2,
73
+ max_preserve_newlines: 0,
74
+ },
75
+ }) {
76
+ glob.sync(htmlFilesPath).forEach((file) => {
76
77
  fs.readFile(file, "utf8", (err, html) => {
77
78
  if (err) console.log(err)
78
79
  if (err) return
@@ -86,16 +87,63 @@ const beautifyHTML = () => {
86
87
  })
87
88
  }
88
89
 
89
- //----------------------------------------------------
90
- // Actions
91
- //----------------------------------------------------
90
+ function webpackBuildWithBeautify({
91
+ webpackCompiler,
92
+ runBeautify = true,
93
+ htmlFilesPath,
94
+ }) {
95
+ webpackCompiler.run((err, stats) => {
96
+ err && console.log(err)
97
+ stats &&
98
+ console.log(
99
+ stats.toString({
100
+ colors: true,
101
+ })
102
+ )
103
+ runBeautify && beautifyHtmlFiles({ htmlFilesPath: htmlFilesPath })
104
+ })
105
+ }
92
106
 
93
- switch (process.argv[2]) {
94
- case undefined:
95
- case "dev":
96
- return webpackDev().listen(8080)
97
- case "build":
98
- return webpackBuild()
99
- default:
107
+ function ministaCommand({
108
+ process,
109
+ webpackCompiler,
110
+ webpackDevServerOptions,
111
+ runBeautify,
112
+ htmlFilesPath,
113
+ }) {
114
+ if (process.argv[2] === undefined || process.argv[2] === "dev") {
115
+ const webpackDev = new webpackDevServer(
116
+ webpackDevServerOptions,
117
+ webpackCompiler
118
+ )
119
+ return webpackDev.start()
120
+ } else if (process.argv[2] === "build") {
121
+ return webpackBuildWithBeautify({
122
+ webpackCompiler: webpackCompiler,
123
+ runBeautify: runBeautify,
124
+ htmlFilesPath: htmlFilesPath,
125
+ })
126
+ } else {
100
127
  return console.log("Command error!\nminista dev or minista build")
128
+ }
101
129
  }
130
+
131
+ const isDev = process.argv[2] !== "build"
132
+ process.env.NODE_ENV = isDev ? "development" : "production"
133
+
134
+ const webpackConfig = getWebpackConfig()
135
+ const userWebpackConfig = getUserWebpackConfig()
136
+ const mergedWebpackConfig = getMergedWebpackConfig({
137
+ config: webpackConfig,
138
+ userConfig: userWebpackConfig,
139
+ })
140
+ const webpackCompiler = webpack(mergedWebpackConfig)
141
+ const webpackDevServerOptions = Object.assign({}, mergedWebpackConfig.devServer)
142
+
143
+ ministaCommand({
144
+ process: process,
145
+ webpackCompiler: webpackCompiler,
146
+ webpackDevServerOptions: webpackDevServerOptions,
147
+ runBeautify: true,
148
+ htmlFilesPath: "dist/**/*.html",
149
+ })
package/index.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ declare module "minista" {
2
+ const render: (element: React.ReactNode) => void
3
+ const Comment: React.ComponentType<{ text: string }>
4
+ }
package/main.js CHANGED
@@ -1,4 +1,3 @@
1
- import React from "react"
2
1
  import { renderToStaticMarkup } from "react-dom/server"
3
2
  import { Helmet } from "react-helmet"
4
3
 
package/package.json CHANGED
@@ -1,15 +1,16 @@
1
1
  {
2
2
  "name": "minista",
3
3
  "description": "Mini static site generator that can be written in React (JSX) for web coding",
4
- "version": "0.10.3",
4
+ "version": "1.0.0",
5
5
  "bin": {
6
6
  "minista": "cli.js"
7
7
  },
8
8
  "main": "./main.js",
9
+ "types": "./index.d.ts",
9
10
  "files": [
10
11
  "main.js",
11
12
  "cli.js",
12
- "postcss.config.js",
13
+ "index.d.ts",
13
14
  "webpack.config.js"
14
15
  ],
15
16
  "license": "MIT",
@@ -27,6 +28,8 @@
27
28
  "coding",
28
29
  "react",
29
30
  "jsx",
31
+ "tsx",
32
+ "typescript",
30
33
  "webpack",
31
34
  "japanese",
32
35
  "minista"
@@ -48,27 +51,31 @@
48
51
  "react-dom": "^17.0.2"
49
52
  },
50
53
  "dependencies": {
51
- "@babel/core": "^7.16.0",
52
- "@babel/preset-env": "^7.16.4",
53
- "@babel/preset-react": "^7.16.0",
54
+ "@babel/core": "^7.16.7",
55
+ "@babel/preset-env": "^7.16.8",
56
+ "@babel/preset-react": "^7.16.7",
57
+ "@babel/preset-typescript": "^7.16.7",
54
58
  "babel-loader": "^8.2.3",
55
- "copy-webpack-plugin": "^10.0.0",
59
+ "copy-webpack-plugin": "^10.2.0",
56
60
  "css-loader": "^6.5.1",
57
- "css-minimizer-webpack-plugin": "^3.2.0",
61
+ "css-minimizer-webpack-plugin": "^3.3.1",
58
62
  "glob": "^7.2.0",
59
63
  "html-replace-webpack-plugin": "^2.6.0",
60
64
  "html-webpack-plugin": "^5.5.0",
61
65
  "js-beautify": "^1.14.0",
62
- "mini-css-extract-plugin": "^2.4.5",
63
- "postcss": "^8.4.4",
66
+ "mini-css-extract-plugin": "^2.4.6",
67
+ "postcss": "^8.4.5",
64
68
  "postcss-flexbugs-fixes": "^5.0.2",
65
69
  "postcss-import": "^14.0.2",
66
70
  "postcss-loader": "^6.2.1",
67
- "postcss-preset-env": "^7.0.1",
71
+ "postcss-preset-env": "^7.2.1",
68
72
  "postcss-sort-media-queries": "^4.2.1",
69
73
  "react-helmet": "^6.1.0",
70
- "webpack": "^5.64.4",
71
- "webpack-dev-server": "^4.6.0",
72
- "webpack-merge": "^5.8.0"
74
+ "svg-sprite-loader": "^6.0.11",
75
+ "ts-loader": "^9.2.6",
76
+ "webpack": "^5.66.0",
77
+ "webpack-dev-server": "^4.7.3",
78
+ "webpack-merge": "^5.8.0",
79
+ "webpack-remove-empty-scripts": "^0.7.2"
73
80
  }
74
81
  }
package/webpack.config.js CHANGED
@@ -4,20 +4,89 @@ const glob = require("glob")
4
4
 
5
5
  const HtmlWebpackPlugin = require("html-webpack-plugin")
6
6
  const HtmlReplaceWebpackPlugin = require("html-replace-webpack-plugin")
7
+ const RemoveEmptyScriptsPlugin = require("webpack-remove-empty-scripts")
7
8
  const MiniCssExtractPlugin = require("mini-css-extract-plugin")
9
+ const SpriteLoaderPlugin = require("svg-sprite-loader/plugin")
8
10
  const CssMinimizerPlugin = require("css-minimizer-webpack-plugin")
9
11
  const TerserPlugin = require("terser-webpack-plugin")
10
12
  const CopyPlugin = require("copy-webpack-plugin")
11
13
 
12
14
  const isDev = process.env.NODE_ENV !== "production"
13
15
 
16
+ const babelJsxOptions = {
17
+ presets: [
18
+ "@babel/preset-env",
19
+ [
20
+ "@babel/preset-react",
21
+ {
22
+ runtime: "automatic",
23
+ },
24
+ ],
25
+ ],
26
+ }
27
+
28
+ const babelTsxOptions = {
29
+ presets: [
30
+ "@babel/preset-env",
31
+ [
32
+ "@babel/preset-react",
33
+ {
34
+ runtime: "automatic",
35
+ },
36
+ ],
37
+ ["@babel/preset-typescript"],
38
+ ],
39
+ }
40
+
14
41
  const postcssOptions = {
15
- plugins: {
16
- "postcss-import": {},
17
- "postcss-flexbugs-fixes": {},
18
- "postcss-sort-media-queries": {},
19
- "postcss-preset-env": {},
20
- },
42
+ plugins: [
43
+ "postcss-import",
44
+ "postcss-flexbugs-fixes",
45
+ "postcss-sort-media-queries",
46
+ "postcss-preset-env",
47
+ ],
48
+ }
49
+
50
+ function switchEntry() {
51
+ const filepath1 = "src/assets/index.js"
52
+ const filepath2 = "src/assets/index.ts"
53
+ const check = fs.existsSync(path.resolve(filepath1))
54
+
55
+ if (check) {
56
+ return "./" + filepath1
57
+ } else {
58
+ return "./" + filepath2
59
+ }
60
+ }
61
+
62
+ function switchBabelOptions(useTsx) {
63
+ const filename1 = "babel.config.js"
64
+ const filename2 = ".babelrc"
65
+ const check1 = fs.existsSync(path.resolve(filename1))
66
+ const check2 = fs.existsSync(path.resolve(filename2))
67
+
68
+ const defaultOptions = useTsx ? babelTsxOptions : babelJsxOptions
69
+
70
+ if (check1) {
71
+ return require(path.resolve(filename1))
72
+ } else if (check2) {
73
+ return JSON.parse(fs.readFileSync(path.resolve(filename2), "utf8"))
74
+ } else {
75
+ return defaultOptions
76
+ }
77
+ }
78
+
79
+ function switchPostcssOptions() {
80
+ const filename = "postcss.config.js"
81
+ const check = fs.existsSync(path.resolve(filename))
82
+
83
+ const defaultOptions = postcssOptions
84
+
85
+ if (check) {
86
+ return require(path.resolve(filename))
87
+ } else {
88
+ return defaultOptions
89
+ }
21
90
  }
22
91
 
23
92
  const webpackConfig = {
@@ -41,11 +110,12 @@ const webpackConfig = {
41
110
  watchOptions: {
42
111
  ignored: ["**/.git/**", "**/node_modules/**"],
43
112
  },
44
- entry: "./src/assets/index.js",
113
+ entry: { bundle: switchEntry() },
45
114
  output: {
46
115
  path: path.resolve("dist"),
47
116
  publicPath: "/",
48
- filename: "assets/scripts.js",
117
+ filename: "assets/[name].js",
118
+ assetModuleFilename: "assets/images/[name].[ext]",
49
119
  },
50
120
  module: {
51
121
  rules: [
@@ -54,9 +124,21 @@ const webpackConfig = {
54
124
  use: [
55
125
  {
56
126
  loader: "babel-loader",
57
- options: {
58
- presets: ["@babel/preset-env", "@babel/react"],
59
- },
127
+ options: switchBabelOptions(),
128
+ },
129
+ ],
130
+ },
131
+ {
132
+ test: /\.ts(|x)$/,
133
+ exclude: /node_modules/,
134
+ use: [
135
+ {
136
+ loader: "babel-loader",
137
+ options: switchBabelOptions(true),
138
+ },
139
+ {
140
+ loader: "ts-loader",
141
+ options: { transpileOnly: true },
60
142
  },
61
143
  ],
62
144
  },
@@ -73,12 +155,10 @@ const webpackConfig = {
73
155
  },
74
156
  {
75
157
  loader: "postcss-loader",
76
- options: fs.existsSync(path.resolve("postcss.config.js"))
77
- ? { sourceMap: isDev }
78
- : {
79
- sourceMap: isDev,
80
- postcssOptions: postcssOptions,
81
- },
158
+ options: {
159
+ sourceMap: isDev,
160
+ postcssOptions: switchPostcssOptions(),
161
+ },
82
162
  },
83
163
  ],
84
164
  },
@@ -95,12 +175,10 @@ const webpackConfig = {
95
175
  },
96
176
  {
97
177
  loader: "postcss-loader",
98
- options: fs.existsSync(path.resolve("postcss.config.js"))
99
- ? { sourceMap: isDev }
100
- : {
101
- sourceMap: isDev,
102
- postcssOptions: postcssOptions,
103
- },
178
+ options: {
179
+ sourceMap: isDev,
180
+ postcssOptions: switchPostcssOptions(),
181
+ },
104
182
  },
105
183
  {
106
184
  loader: "sass-loader",
@@ -120,6 +198,19 @@ const webpackConfig = {
120
198
  filename: "assets/fonts/[name].[ext]",
121
199
  },
122
200
  },
201
+ {
202
+ test: /icons\/.*\.svg$/,
203
+ use: [
204
+ {
205
+ loader: "svg-sprite-loader",
206
+ options: {
207
+ extract: true,
208
+ spriteFilename: "assets/icons.svg",
209
+ runtimeCompat: true,
210
+ },
211
+ },
212
+ ],
213
+ },
123
214
  ],
124
215
  },
125
216
  plugins: [
@@ -129,8 +220,12 @@ const webpackConfig = {
129
220
  replacement: "<!-- $1 -->",
130
221
  },
131
222
  ]),
223
+ new RemoveEmptyScriptsPlugin(),
132
224
  new MiniCssExtractPlugin({
133
- filename: "assets/styles.css",
225
+ filename: "assets/[name].css",
226
+ }),
227
+ new SpriteLoaderPlugin({
228
+ plainSprite: true,
134
229
  }),
135
230
  new CopyPlugin({
136
231
  patterns: [
@@ -140,15 +235,27 @@ const webpackConfig = {
140
235
  ],
141
236
  optimization: {
142
237
  minimize: !isDev,
143
- minimizer: [new CssMinimizerPlugin({}), new TerserPlugin({})],
238
+ minimizer: [
239
+ new CssMinimizerPlugin({
240
+ minimizerOptions: {
241
+ preset: [
242
+ "default",
243
+ {
244
+ cssDeclarationSorter: false,
245
+ },
246
+ ],
247
+ },
248
+ }),
249
+ new TerserPlugin({}),
250
+ ],
144
251
  },
145
252
  resolve: {
146
- extensions: [".js", ".jsx"],
253
+ extensions: [".js", ".jsx", ".ts", ".tsx"],
147
254
  },
148
255
  }
149
256
 
150
257
  glob
151
- .sync("**/*.js", {
258
+ .sync("**/*.{js,jsx,ts,tsx}", {
152
259
  cwd: "src/pages",
153
260
  })
154
261
  .forEach((file) => {