@tenjuu99/blog 0.1.3 → 0.1.6

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/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright 2024 Amashige Seiji
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -1,21 +1,18 @@
1
1
  # blog template
2
2
 
3
- ## プレビュー
4
-
5
- 以下のコマンドでプレビューできます。
3
+ ## setup
6
4
 
7
5
  ```
8
- npm run watch
6
+ npm i @tenjuu99/blog
9
7
  ```
10
8
 
11
- `http://localhost:8000/`
12
-
13
- デフォルトでは8000ポートを利用しますが、環境変数を使ってポート番号を上書きできます。
14
-
15
9
  ```
16
- PORT=8001 npm run watch
10
+ npx create-blog
11
+ npx server
17
12
  ```
18
13
 
14
+ `http://localhost:8000` にアクセスできます
15
+
19
16
  ## 記事を書く
20
17
 
21
18
  `./data/` 以下にマークダウンファイルを入稿します。
@@ -122,24 +119,7 @@ This is else content.
122
119
  ### SCRIPT
123
120
 
124
121
  ```markdown
125
- {script}
126
- // write javascript and return value
127
- {/script}
122
+ <script type="ssg">
123
+ return 'これはスクリプトが実行された結果出力されました。'
124
+ </script>
128
125
  ```
129
-
130
- ## デプロイ
131
-
132
- AWS S3 にデプロイするには、 `.github/workflow/deploy.yml.sample` を `.github/workflow/deploy.yml` にコピーします。
133
- また、 `.env.prod` を作成して、以下の値を登録します。
134
-
135
- ```
136
- SITE_NAME: テストサイト
137
- URL_BASE: https://example.com
138
- GTAG_ID: G-xxxx
139
- ```
140
-
141
- GitHub のリポジトリで、`settings > Secrets and variables > Actions` から、以下の変数を登録します。
142
-
143
- * `AWS_ACCESS_KEY_ID`
144
- * `AWS_SECRET_ACCESS_KEY_ID`
145
- * `S3_URL`
package/bin/new ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env bash
2
+
3
+ mkdir -p "$(pwd)/src/pages"
4
+ echo "create src/pages"
5
+ mkdir -p "$(pwd)/src/template"
6
+ echo "create src/template"
7
+ mkdir -p "$(pwd)/src/css"
8
+ echo "create src/css"
9
+ mkdir -p "$(pwd)/src/image"
10
+ echo "create src/image"
11
+
12
+ mkdir "$(pwd)/.cache"
13
+ echo "[]" > "$(pwd)/.cache/index.json"
14
+
15
+ echo 'dist/*
16
+ node_modules/
17
+ .env
18
+ .cache
19
+ ' >> .gitignore
20
+
21
+ echo '{
22
+ "site_name": "rewrite here",
23
+ "url_base": "http://localhost:8000",
24
+ "src_dir": "src",
25
+ "dist_dir": "dist",
26
+ "distribute_raw": "image",
27
+ "helper": "helper/index.js"
28
+ }' > "$(pwd)/blog.json"
29
+ echo "create blog.json"
30
+
31
+ cp -R "$(pwd)/node_modules/@tenjuu99/blog/src-sample/" "$(pwd)/src"
package/lib/config.js ADDED
@@ -0,0 +1,32 @@
1
+ import { readFileSync, existsSync } from 'node:fs'
2
+
3
+ const rootDir = process.cwd()
4
+ const config = {
5
+ "site_name": "default",
6
+ "url_base": "http://localhost:8000",
7
+ "src_dir": "src",
8
+ "dist_dir": "dist",
9
+ "distribute_raw": "image",
10
+ "relative_path": "",
11
+ "helper": ""
12
+ }
13
+ try {
14
+ const file = rootDir + '/blog.json'
15
+ if (existsSync(file)) {
16
+ const configOverride = JSON.parse(readFileSync(file, 'utf8'))
17
+ for (const item in configOverride) {
18
+ config[item] = configOverride[item]
19
+ }
20
+ }
21
+ const keys = Object.keys(process.env)
22
+ for (const item in config) {
23
+ const upper = item.toUpperCase()
24
+ if (keys.includes(upper)) {
25
+ config[item] = process.env[upper]
26
+ }
27
+ }
28
+ } catch (e) {
29
+ console.log(e)
30
+ }
31
+
32
+ export default config
@@ -6,6 +6,7 @@ import path from 'path'
6
6
  import { distDir as distRoot, cssDir } from './dir.js'
7
7
  import { watchers } from './watcher.js'
8
8
  import { styleText } from 'node:util'
9
+ import config from './config.js'
9
10
 
10
11
  let cacheBuster = {}
11
12
  const cacheBusterQuery = 't'
@@ -55,7 +56,7 @@ const applyCss = async (text) => {
55
56
  })
56
57
  for (const cssDist of target) {
57
58
  const cacheBuster = await cssGenerator(cssDist.src, cssDist.dist)
58
- text = text.replace(cssDist.matched, `${process.env.RELATIVE_PATH || ''}${cssDist.dist}?${cacheBusterQuery}=${cacheBuster}`)
59
+ text = text.replace(cssDist.matched, `${config.relative_path}${cssDist.dist}?${cacheBusterQuery}=${cacheBuster}`)
59
60
  }
60
61
  return text
61
62
  }
package/lib/dir.js CHANGED
@@ -1,6 +1,8 @@
1
+ import config from './config.js'
2
+
1
3
  const rootDir = process.cwd()
2
- const srcDir = `${rootDir}/${process.env.SRC_DIR}`
3
- const distDir = `${rootDir}/${process.env.DIST_DIR}`
4
+ const srcDir = `${rootDir}/${config.src_dir}`
5
+ const distDir = `${rootDir}/${config.dist_dir}`
4
6
  const pageDir = `${srcDir}/pages`
5
7
  const templateDir = `${srcDir}/template`
6
8
  const cssDir = `${srcDir}/css`
package/lib/distribute.js CHANGED
@@ -4,6 +4,7 @@ import path from 'path'
4
4
  import { minifyHtml } from './minify.js'
5
5
  import render from './render.js'
6
6
  import { styleText } from 'node:util'
7
+ import config from './config.js'
7
8
 
8
9
  const distribute = async (data, deleted, srcDir, distDir) => {
9
10
  if (deleted) {
@@ -22,7 +23,7 @@ const distribute = async (data, deleted, srcDir, distDir) => {
22
23
  console.log(styleText('green', '[generate]'), writeTo)
23
24
  })
24
25
  }
25
- const distributeRaw = process.env.DISTRIBUTE_RAW.split(',')
26
+ const distributeRaw = config.distribute_raw.split(',')
26
27
  distributeRaw.forEach((copyDir) => {
27
28
  fs.readdir(`${srcDir}/${copyDir}/`).then(async files => {
28
29
  await fs.stat(`${distDir}/${copyDir}/`).catch(async err => await fs.mkdir(`${distDir}/${copyDir}/`))
package/lib/filter.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import * as helper from '../helper/index.js'
2
2
  import includeFilter from './includeFilter.js'
3
3
  import { srcDir } from './dir.js'
4
+ import config from './config.js'
5
+ console.log(config)
4
6
 
5
7
  /**
6
8
  * @param {string} text
@@ -129,8 +131,8 @@ const replaceScriptFilter = async (text, variables) => {
129
131
  for (const script of scripts) {
130
132
  let helperMerged = {...helper}
131
133
  // env.HELPER が定義されていれば追加ヘルパーとして扱う
132
- if (process.env.HELPER) {
133
- const additional = await import(`${srcDir}/${process.env.HELPER}`)
134
+ if (config.helper) {
135
+ const additional = await import(`${srcDir}/${config.helper}`)
134
136
  helperMerged = Object.assign(helperMerged, additional)
135
137
  }
136
138
  let result = new Function('helper', 'variables', script.script)(helperMerged, variables)
package/lib/indexer.js CHANGED
@@ -1,30 +1,42 @@
1
1
  "use strict"
2
- import fs from "node:fs/promises";
2
+ import { writeFile, readFile } from "node:fs/promises";
3
+ import { readdirSync, existsSync, mkdirSync } from "node:fs";
3
4
  import { pageDir, cacheDir } from './dir.js'
4
5
  import makePageData from './pageData.js'
5
6
 
6
7
  const indexFile = `${cacheDir}/index.json`
7
8
 
9
+ let newIndex = []
8
10
  let allData = {}
9
11
  let deleted = []
10
12
 
11
- const indexing = async () => {
12
- const oldIndex = await fs.readFile(indexFile, 'utf8').then(text => JSON.parse(text)).catch(error => [])
13
+ const collect = (dir, files = {}, namePrefix = '') => {
14
+ const dirents = readdirSync(dir, { withFileTypes: true })
15
+ dirents.forEach((dirent) => {
16
+ if (dirent.isDirectory()) {
17
+ collect(`${dirent.path}/${dirent.name}`, files, namePrefix + dirent.name + '/')
18
+ } else {
19
+ if (dirent.name.match(/\.(md|html)$/)) {
20
+ const pageData = makePageData(`${namePrefix}${dirent.name}`)
21
+ allData[pageData.name] = pageData
22
+ const { name, url, __output } = pageData
23
+ newIndex.push({ name, url, __output })
24
+ }
25
+ }
26
+ })
27
+ }
13
28
 
14
- const newIndex = []
29
+ const indexing = async () => {
30
+ newIndex = []
15
31
  allData = {}
16
32
  deleted = []
17
- await fs.readdir(pageDir).then(files => {
18
- files
19
- .filter(fileName => fileName.match('\.(md|html)$'))
20
- .forEach(file => {
21
- const metaData = makePageData(file)
22
- allData[metaData.name] = metaData
23
- const { name, url, __output } = metaData
24
- newIndex.push({ name, url, __output })
25
- })
26
- })
27
- fs.writeFile(indexFile, JSON.stringify(newIndex))
33
+ if (!existsSync(cacheDir)) {
34
+ mkdirSync(cacheDir)
35
+ }
36
+ const oldIndex = await readFile(indexFile, 'utf8').then(text => JSON.parse(text)).catch(error => [])
37
+
38
+ collect(pageDir)
39
+ writeFile(indexFile, JSON.stringify(newIndex))
28
40
 
29
41
  // 旧インデックスから差分を計算して削除対象をピックアップする
30
42
  deleted = oldIndex.filter(oi => !newIndex.map(ni => ni.__output).includes(oi.__output))
package/lib/pageData.js CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict"
2
2
  import fs from "node:fs";
3
3
  import { pageDir } from './dir.js'
4
+ import config from './config.js'
4
5
 
5
6
  const load = (path) => {
6
7
  return fs.readFileSync(path, 'utf8')
@@ -26,11 +27,11 @@ const parse = (content, name, ext) => {
26
27
  index: true,
27
28
  noindex: false,
28
29
  lang: 'ja',
29
- site_name: process.env.SITE_NAME,
30
- url_base: process.env.URL_BASE,
31
- gtag_id: process.env.GTAG_ID,
30
+ site_name: config.site_name,
31
+ url_base: config.url_base,
32
+ gtag_id: config.gtag_id,
32
33
  markdown: markdownReplaced,
33
- relative_path: process.env.RELATIVE_PATH || '',
34
+ relative_path: config.relative_path || '',
34
35
  template: 'default.html',
35
36
  ext: 'html',
36
37
  __output: `/${name}.html`,
package/package.json CHANGED
@@ -1,16 +1,17 @@
1
1
  {
2
2
  "name": "@tenjuu99/blog",
3
- "version": "0.1.3",
3
+ "version": "0.1.6",
4
4
  "description": "blog template",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
- "dev": "eval $(cat .env | tr \"\n\" \" \") node bin/server",
8
- "generate": "eval $(cat .env | tr \"\n\" \" \") node bin/generate",
7
+ "dev": "node bin/server",
8
+ "generate": "node bin/generate",
9
9
  "test": "echo \"Error: no test specified\" && exit 1"
10
10
  },
11
11
  "bin": {
12
12
  "generate": "bin/generate",
13
- "server": "bin/server"
13
+ "server": "bin/server",
14
+ "create-blog": "bin/new"
14
15
  },
15
16
  "author": "AmashigeSeiji",
16
17
  "repository": {
@@ -25,5 +26,14 @@
25
26
  "type": "module",
26
27
  "engines": {
27
28
  "node": ">=21.7"
29
+ },
30
+ "files": [
31
+ "lib",
32
+ "bin",
33
+ "helper",
34
+ "src-sample"
35
+ ],
36
+ "publishConfig": {
37
+ "access": "public"
28
38
  }
29
39
  }
package/.env.prod.sample DELETED
@@ -1,8 +0,0 @@
1
- SITE_NAME=test_blog
2
- GTAG_ID=
3
- URL_BASE=https://amashigeseiji.github.io/blog_template
4
- RELATIVE_PATH=/tenjuu99-blog
5
- SRC_DIR=src-sample
6
- DIST_DIR=dist
7
- DISTRIBUTE_RAW=image
8
- HELPER=helper/index.js
package/.env.sample DELETED
@@ -1,8 +0,0 @@
1
- SITE_NAME=test_blog
2
- GTAG_ID=
3
- URL_BASE=http://localhost:8000
4
- RELATIVE_PATH=
5
- SRC_DIR=src-sample
6
- DIST_DIR=dist
7
- DISTRIBUTE_RAW=image
8
- HELPER=helper/index.js
@@ -1,51 +0,0 @@
1
- name: Build html and deploy to S3
2
- on:
3
- push:
4
- branches:
5
- - main
6
- jobs:
7
- build:
8
- runs-on: ubuntu-latest
9
- steps:
10
- - name: Checkout
11
- uses: actions/checkout@master
12
-
13
- - name: npm install
14
- run: npm install --production
15
-
16
- - name: Build
17
- run: npm run generate:prod
18
-
19
- - name: Deploy
20
- env:
21
- AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
22
- AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
23
- run: |
24
- aws s3 sync \
25
- --region ap-northeast-1 \
26
- --exact-timestamps \
27
- --exclude .gitignore \
28
- --exclude '*.css' \
29
- --exclude 'image/' \
30
- --delete \
31
- --metadata-directive REPLACE \
32
- --cache-control "max-age=86400, no-cache, public" \
33
- dist/ s3://${{ secrets.S3_URL }}/
34
-
35
- aws s3 sync \
36
- --region ap-northeast-1 \
37
- --exact-timestamps \
38
- --exclude .gitignore \
39
- --delete \
40
- --metadata-directive REPLACE \
41
- --cache-control "max-age=31536000, public" \
42
- dist/css/ s3://${{ secrets.S3_URL }}/css/
43
-
44
- aws s3 sync \
45
- --region ap-northeast-1 \
46
- --exact-timestamps \
47
- --exclude .gitignore \
48
- --delete \
49
- --metadata-directive REPLACE \
50
- --cache-control "max-age=86400, public" \
51
- dist/image/ s3://${{ secrets.S3_URL }}/image/
@@ -1,52 +0,0 @@
1
- # Simple workflow for deploying static content to GitHub Pages
2
- name: Deploy static content to Pages
3
-
4
- on:
5
- push:
6
- branches:
7
- - main
8
- workflow_dispatch:
9
-
10
- # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
11
- permissions:
12
- contents: read
13
- pages: write
14
- id-token: write
15
-
16
- # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
17
- # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
18
- concurrency:
19
- group: "pages"
20
- cancel-in-progress: false
21
-
22
- jobs:
23
- deploy:
24
- environment:
25
- name: github-pages
26
- url: ${{ steps.deployment.outputs.page_url }}
27
- runs-on: ubuntu-latest
28
- steps:
29
- - name: Checkout
30
- uses: actions/checkout@master
31
-
32
- - name: Use nodejs
33
- uses: actions/setup-node@v4
34
- with:
35
- node-version: '22.x'
36
-
37
- - name: npm install
38
- run: npm install --omit=dev
39
-
40
- - name: Build
41
- run: cp .env.prod.sample .env && npm run generate
42
-
43
- - name: Setup Pages
44
- uses: actions/configure-pages@v4
45
- - name: Upload artifact
46
- uses: actions/upload-pages-artifact@v3
47
- with:
48
- # Upload dist
49
- path: './dist/'
50
- - name: Deploy to GitHub Pages
51
- id: deployment
52
- uses: actions/deploy-pages@v4
package/.gitignore DELETED
@@ -1,9 +0,0 @@
1
- node_modules/
2
- dist/*
3
- !.gitignore
4
- !favicon.ico
5
- data/index.json
6
- .DS_Store
7
-
8
- .env
9
- .cache/
package/.node-version DELETED
@@ -1 +0,0 @@
1
- 22.7.0
package/helper/add.js DELETED
@@ -1,3 +0,0 @@
1
- export function hogehoge() {
2
- return 'hogehoge'
3
- }
@@ -1,67 +0,0 @@
1
- /**
2
- * @param {string} condition
3
- * @params {object} variables
4
- * @return {bool}
5
- */
6
- const ifConditionEvaluator = (condition, variables) => {
7
- if (condition.includes('=')) {
8
- const segmented = condition.match(/(?<left>[\S]+)\s(?<operator>!=|==)\s(?<right>[\S]+)/)
9
- let {left, operator, right} = segmented.groups
10
- if (variables.hasOwnProperty(left)) {
11
- left = variables[left]
12
- } else {
13
- try {
14
- left = eval(left)
15
- } catch (e) {
16
- left = undefined
17
- }
18
- }
19
- if (variables.hasOwnProperty(right)) {
20
- right = variables[right]
21
- } else {
22
- try {
23
- right = eval(right)
24
- } catch (e) {
25
- right = undefined
26
- }
27
- }
28
- switch (operator) {
29
- case '==':
30
- return left == right
31
- case '!=':
32
- return left != right
33
- }
34
- } else {
35
- if (variables.hasOwnProperty(condition)) {
36
- return !!variables[condition]
37
- }
38
- return false
39
- }
40
- }
41
-
42
- const ifRegexp =
43
- new RegExp(/(\{|<)if\s(?<condition>[\s\S]+?)(}|>)(?<content>[\s\S]*?)((\{|<)else(\}|>)(?<elsecontent>[\s\S]*?))?(\{<)\/if(>|})/g)
44
-
45
- /**
46
- * @param {string} text
47
- * @param {object} variables
48
- * @returns {string}
49
- */
50
- const replaceIfFilter = (text, variables) => {
51
- const matched = [...text.matchAll(ifRegexp)]
52
- for (const item of matched) {
53
- const target = item[0]
54
- const content = item.groups.content
55
- const elseContent = item.groups.elsecontent
56
- if (ifConditionEvaluator(item.groups.condition, variables)) {
57
- text = text.replace(target, content)
58
- } else if (elseContent) {
59
- text = text.replace(target, elseContent)
60
- } else {
61
- text = text.replace(target, '')
62
- }
63
- }
64
- return text
65
- }
66
-
67
- export default replaceIfFilter
@@ -1,71 +0,0 @@
1
- import * as helper from '../helper/index.js'
2
- import vm from 'vm'
3
-
4
- /**
5
- * 配列を再帰的に順不同リストに変換する
6
- * @param {Array|string} arrayOrText
7
- * @returns {mixed}
8
- */
9
- const arrayToList = (arrayOrText) => {
10
- if (typeof arrayOrText === 'string') {
11
- return `<li>${arrayOrText}</li>`
12
- }
13
- if (Array.isArray(arrayOrText)) {
14
- let resultListText = '<ul>'
15
- for (const item of arrayOrText) {
16
- if (Array.isArray(item)) {
17
- resultListText += `<li>${arrayToList(item)}</li>`
18
- } else {
19
- resultListText += `<li>${item}</li>`
20
- }
21
- }
22
- resultListText += '</ul>'
23
- arrayOrText = resultListText
24
- }
25
- return arrayOrText
26
- }
27
-
28
- const replaceScriptFilter = async (text, variables) => {
29
- let replaced = text
30
- const scriptRegexp = new RegExp(/({script}|\<script\s.*type="ssg".*>)(?<script>[\s\S]*?)(\{\/script}|\<\/script>)/g)
31
- const scripts = [...text.matchAll(scriptRegexp)].map((matched) => {
32
- return {
33
- replace: matched[0],
34
- script: matched.groups.script.trim("\n"),
35
- }
36
- })
37
- const context = vm.createContext({
38
- helper,
39
- variables,
40
- })
41
- for (const script of scripts) {
42
- const s = new vm.Script(script.script)
43
- console.log(script.script)
44
- console.log(s)
45
- console.log('------------------------------------------------')
46
- const func = vm.runInContext(script, context)
47
- console.log(func)
48
- let result = await func(variables, helper)
49
- if (result instanceof Promise) {
50
- result = await result
51
- }
52
- if (Array.isArray(result)) {
53
- result = arrayToList(result)
54
- } else if (typeof result === 'object') {
55
- const resultText = []
56
- for (const key in result) {
57
- resultText.push(`<h3>${key}</h3>`)
58
- if (Array.isArray(result[key])) {
59
- resultText.push(arrayToList(result[key]))
60
- } else {
61
- resultText.push(`<p>${result[key]}</p>`)
62
- }
63
- }
64
- result = resultText.join('\n')
65
- }
66
- replaced = replaced.replace(script.replace, result)
67
- }
68
- return replaced
69
- }
70
-
71
- export default replaceScriptFilter
package/performance.js DELETED
@@ -1,22 +0,0 @@
1
- "use strict"
2
- import distribute from './lib/distribute.js'
3
- import { indexing, allData, deleted } from './lib/indexer.js'
4
- import { srcDir, distDir } from './lib/dir.js'
5
-
6
- process.env.FORCE_BUILD = true
7
- const doBuild = async () => {
8
- const start = performance.now()
9
- await indexing()
10
- await distribute(allData, deleted, srcDir, distDir)
11
- const end = performance.now()
12
- return end - start
13
- }
14
- const times = 100
15
- let executed = 0
16
- for (let i = 0; i < times; i++) {
17
- // console.log(await executed())
18
- const buildTime = await doBuild()
19
- executed += (buildTime)
20
- console.log(buildTime)
21
- }
22
- console.log('build average: 100 times: ' + (executed/times) + "ms")
File without changes
File without changes
File without changes
File without changes
@@ -1,6 +0,0 @@
1
- ---
2
- title: abc
3
- url: /abc
4
- published: 2024-08-31
5
- ---
6
- hoge
@@ -1,3 +0,0 @@
1
- ## fuga
2
-
3
- これは変数がないです
@@ -1,8 +0,0 @@
1
- ---
2
- title: hoge
3
- url: /hoge
4
- published: 2024/03/19 00:00
5
- ifTrueVariable: true
6
- ---
7
-
8
- hoge
File without changes