minista 0.11.0 → 1.0.1

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 = () => {
60
+ const PageHome = () => {
61
61
  return render( // Required!
62
62
  <h1>Hello</h1>
63
63
  )
64
64
  }
65
65
 
66
- export default Home
66
+ export default PageHome
67
67
  ```
68
68
 
69
69
  #### Develop
@@ -88,12 +88,12 @@ $ minista build
88
88
 
89
89
  #### Input
90
90
 
91
+ <!-- prettier-ignore -->
91
92
  ```js
92
- import React from "react"
93
93
  import { render, Comment } from "minista"
94
94
 
95
- const Home = () => {
96
- return render(
95
+ const PageHome = () => {
96
+ return render( // Required!
97
97
  <>
98
98
  <Comment text="Comment Test" />
99
99
  <h1>Hello</h1>
@@ -101,7 +101,7 @@ const Home = () => {
101
101
  )
102
102
  }
103
103
 
104
- export default Home
104
+ export default PageHome
105
105
  ```
106
106
 
107
107
  #### output
@@ -126,22 +126,38 @@ export default Home
126
126
  プロジェクトの root に `webpack.config.js` を配置することで設定をマージできます。
127
127
 
128
128
  ```js
129
- // Example
129
+ //----------------------------------------------------
130
+ // Example: User > webpack.config.js
131
+ //----------------------------------------------------
132
+
133
+ // No installation required.
134
+ const MiniCssExtractPlugin = require("mini-css-extract-plugin")
135
+ const CopyPlugin = require("copy-webpack-plugin")
136
+
137
+ // Example of dev mode
138
+ const isDev = process.env.NODE_ENV !== "production"
139
+
130
140
  const webpackConfig = {
141
+ // Merge
131
142
  devServer: {
132
143
  open: ["/index.html"],
133
144
  },
134
145
  plugins: [
146
+ // Replace
135
147
  new MiniCssExtractPlugin({
136
- filename: "assets/custom.css",
148
+ filename: "assets/[name].css",
137
149
  }),
150
+ // Replace
138
151
  new CopyPlugin({
139
152
  patterns: [{ from: "./static", to: "./", noErrorOnMissing: true }],
140
153
  }),
141
154
  ],
155
+
156
+ // All optimization is replaced.
142
157
  optimization: {
158
+ minimize: !isDev,
143
159
  minimizer: [
144
- /* All replacements */
160
+ /* Replace plugins */
145
161
  ],
146
162
  },
147
163
  }
@@ -149,18 +165,102 @@ const webpackConfig = {
149
165
  module.exports = webpackConfig
150
166
  ```
151
167
 
168
+ ### TypeScript
169
+
170
+ TypeScript `.tsx` でページを作成する場合はモジュールを追加し `tsconfig.json` をプロジェクトの root に配置。エントリーポイントとして `src/assets/index.ts` があれば `src/assets/index.js` の代わりに使用します。
171
+
172
+ ```bash
173
+ $ npm install --save-dev typescript @types/react @types/react-dom
174
+ ```
175
+
176
+ ```json
177
+ {
178
+ "compilerOptions": {
179
+ "target": "esnext",
180
+ "module": "esnext",
181
+ "baseUrl": ".",
182
+ "allowJs": true,
183
+ "strict": true,
184
+ "noImplicitAny": false,
185
+ "strictNullChecks": true,
186
+ "noUnusedLocals": true,
187
+ "noUnusedParameters": true,
188
+ "noImplicitReturns": true,
189
+ "moduleResolution": "node",
190
+ "esModuleInterop": true,
191
+ "isolatedModules": false,
192
+ "skipLibCheck": true,
193
+ "forceConsistentCasingInFileNames": true,
194
+ "resolveJsonModule": true,
195
+ "jsx": "react-jsx"
196
+ },
197
+ "include": ["**/*.ts", "**/*.tsx"],
198
+ "exclude": ["node_modules", "dist", "webpack.config.js"]
199
+ }
200
+ ```
201
+
202
+ ```bash
203
+ # ----------------------------------------------------
204
+ # Directory Example
205
+ # ----------------------------------------------------
206
+
207
+ public # Copy root
208
+ src
209
+ ├── assets
210
+ │ └── index.ts (or index.js) # Required!
211
+ ├── components
212
+ │ └── layout.js
213
+ └── pages # Required!
214
+ ├── about
215
+ │ └── index.tsx
216
+ └── index.tsx
217
+ ```
218
+
219
+ ### Babel
220
+
221
+ Babel はプロジェクトの root に `.babelrc` もしくは `babel.config.js` を配置することで設定を上書きできます。カスタマイズしない場合は以下の設定が適応されます。
222
+
223
+ ```js
224
+ // JavaScript
225
+ const babelJsxOptions = {
226
+ presets: [
227
+ "@babel/preset-env",
228
+ [
229
+ "@babel/preset-react",
230
+ {
231
+ runtime: "automatic",
232
+ },
233
+ ],
234
+ ],
235
+ }
236
+
237
+ // TypeScript
238
+ const babelTsxOptions = {
239
+ presets: [
240
+ "@babel/preset-env",
241
+ [
242
+ "@babel/preset-react",
243
+ {
244
+ runtime: "automatic",
245
+ },
246
+ ],
247
+ ["@babel/preset-typescript"],
248
+ ],
249
+ }
250
+ ```
251
+
152
252
  ### PostCSS
153
253
 
154
254
  PostCSS はゼロコンフィグで以下のプラグインが適応されますが、プロジェクトの root に `postcss.config.js` を配置することで設定を上書きできます。
155
255
 
156
256
  ```js
157
257
  module.exports = {
158
- plugins: {
159
- "postcss-import": {},
160
- "postcss-flexbugs-fixes": {},
161
- "postcss-sort-media-queries": {},
162
- "postcss-preset-env": {},
163
- },
258
+ plugins: [
259
+ "postcss-import",
260
+ "postcss-flexbugs-fixes",
261
+ "postcss-sort-media-queries",
262
+ "postcss-preset-env",
263
+ ],
164
264
  }
165
265
  ```
166
266
 
@@ -172,18 +272,66 @@ module.exports = {
172
272
  $ npm install --save-dev sass-loader sass
173
273
  ```
174
274
 
275
+ ### Style only
276
+
277
+ プロジェクトに JavaScript が全く必要ない場合はエントリーポイントを CSS ファイルに変更します。これにより空の JavaScript ファイルを出力することなく納品用データを生成できます。
278
+
279
+ ```js
280
+ //----------------------------------------------------
281
+ // Example: User > webpack.config.js
282
+ //----------------------------------------------------
283
+
284
+ const webpackConfig = {
285
+ entry: { bundle: "./src/assets/index.css" },
286
+ }
287
+
288
+ module.exports = webpackConfig
289
+ ```
290
+
291
+ ### SVG sprite icons
292
+
293
+ `src/assets/icons` ディレクトリに SVG ファイルを置くと SVG スプライトアイコンの `dist/assets/icons.svg` が生成されます。以下のようなコンポーネントを作ることでアイコンを呼び出せます。
294
+
295
+ ```js
296
+ // Example: ./src/components/svg-sprite-icon.tsx
297
+ export interface SvgSpriteIconProps {
298
+ iconId?: string;
299
+ }
300
+
301
+ export const SvgSpriteIcon = (props: SvgSpriteIconProps) => {
302
+ const { iconId } = props
303
+ return (
304
+ <svg className="icon" role="img">
305
+ <use xlinkHref={`/assets/icons.svg#${iconId}`} />
306
+ </svg>
307
+ )
308
+ }
309
+ ```
310
+
311
+ ```html
312
+ <!-- dist html -->
313
+ <svg role="img" class="icon">
314
+ <use xlink:href="/assets/icons.svg#star"></use>
315
+ </svg>
316
+ ```
317
+
175
318
  ## Media
176
319
 
177
320
  - [React(JSX)で書けるコーディング用 SSG - minista v0](https://zenn.dev/qrac/articles/7537521afcd1bf)
178
321
 
179
322
  ## Respect
180
323
 
181
- - [Charge — an opinionated, zero-config static site generator](https://charge.js.org/)
182
324
  - [Next.js by Vercel - The React Framework](https://nextjs.org/)
325
+ - [Charge — an opinionated, zero-config static site generator](https://charge.js.org/)
326
+ - [Eleventy, a simpler static site generator.](https://www.11ty.dev/)
183
327
  - [Node Interface | webpack](https://webpack.js.org/api/node/)
328
+ - [natemoo-re/microsite](https://github.com/natemoo-re/microsite)
329
+ - [Astro](https://astro.build/)
184
330
  - [テンプレートエンジンに React を使いつつ、きれいな HTML を生成したいんじゃ!!](https://zenn.dev/otsukayuhi/articles/e52651b4e2c5ae7c4a17)
185
331
  - [EJS をやめて React で HTML を書く](https://zenn.dev/hisho/scraps/4ef6c6106a6395)
186
332
  - [MPA(マルチページアプリ)で webpack を使う](https://www.key-p.com/blog/staff/archives/107125)
333
+ - [HTML コーディングでも React+TypeScript の開発体験を得る](https://zenn.dev/nanaki14/articles/html-template-react)
334
+ - [Astro と microCMS でポートフォリオサイトを作る](https://zenn.dev/takanorip/articles/c75717c280c81d)
187
335
 
188
336
  ## License
189
337
 
package/cli.js CHANGED
@@ -3,7 +3,7 @@ const fs = require("fs")
3
3
  const path = require("path")
4
4
  const glob = require("glob")
5
5
  const webpack = require("webpack")
6
- const { mergeWithRules, unique } = require("webpack-merge")
6
+ const { mergeWithCustomize, customizeObject, unique } = require("webpack-merge")
7
7
  const webpackDevServer = require("webpack-dev-server")
8
8
  const beautify = require("js-beautify")
9
9
 
@@ -20,17 +20,16 @@ function getUserWebpackConfig() {
20
20
  }
21
21
 
22
22
  function getMergedWebpackConfig({ config, userConfig }) {
23
- const mergedConfig = mergeWithRules({
24
- optimization: {
25
- minimizer: "replace",
26
- },
23
+ const mergedConfig = mergeWithCustomize({
24
+ customizeObject: customizeObject({
25
+ optimization: "replace",
26
+ }),
27
27
  customizeArray: unique(
28
28
  "plugins",
29
29
  ["MiniCssExtractPlugin", "CopyPlugin"],
30
30
  (plugin) => plugin.constructor && plugin.constructor.name
31
31
  ),
32
32
  })(config, userConfig)
33
- console.log(mergedConfig)
34
33
  const filterdPlugins = filterWebpackPlugins({
35
34
  plugins: mergedConfig.plugins,
36
35
  })
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.11.0",
4
+ "version": "1.0.1",
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.5",
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) => {