create-pugkit 1.0.0-beta.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 ADDED
@@ -0,0 +1,44 @@
1
+ # create-pugkit
2
+
3
+ ## About
4
+
5
+ [pugkit](https://github.com/a_tokuhara/pugkit) を使用した静的サイト制作のスターターキットです。
6
+
7
+ ## Usage
8
+
9
+ ### Interactive
10
+
11
+ ```sh
12
+ npm create pugkit@latest
13
+ ```
14
+
15
+ ### With project name
16
+
17
+ プロジェクト名を指定して作成します。
18
+
19
+ ```sh
20
+ npm create pugkit@latest my-pugkit-project
21
+ ```
22
+
23
+ ### Current directory
24
+
25
+ カレントディレクトリに作成します。
26
+
27
+ ```sh
28
+ npm create pugkit@latest .
29
+ ```
30
+
31
+ ## Next Steps
32
+
33
+ プロジェクト作成後の手順:
34
+
35
+ ```sh
36
+ cd my-pugkit-project
37
+ npm install
38
+ npm build
39
+ npm run dev
40
+ ```
41
+
42
+ ## License
43
+
44
+ MIT
package/cli/index.mjs ADDED
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readFileSync } from 'node:fs'
4
+ import { fileURLToPath } from 'node:url'
5
+ import path from 'node:path'
6
+ import fs from 'fs-extra'
7
+ import pc from 'picocolors'
8
+ import { cac } from 'cac'
9
+ import prompts from 'prompts'
10
+
11
+ const __filename = fileURLToPath(import.meta.url)
12
+ const __dirname = path.dirname(__filename)
13
+
14
+ function pkgVersion() {
15
+ const pkgPath = path.join(__dirname, '../package.json')
16
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'))
17
+ return pkg.version
18
+ }
19
+
20
+ function log(message) {
21
+ console.log(`${pc.cyan(pc.bold('CREATE-PUGKIT'))} ${pc.dim(`v${pkgVersion()}`)} ${message}`)
22
+ }
23
+
24
+ function mkdirp(dir) {
25
+ try {
26
+ fs.mkdirSync(dir, { recursive: true })
27
+ } catch (err) {
28
+ if (err.code === 'EEXIST') return
29
+ throw err
30
+ }
31
+ }
32
+
33
+ async function main(root, options) {
34
+ const cwd = path.resolve(process.cwd(), root || '.')
35
+ const current = root === '.'
36
+ const projectName = current ? path.basename(process.cwd()) : root
37
+
38
+ const questions = {
39
+ overwrite: {
40
+ type: 'confirm',
41
+ name: 'overwrite',
42
+ message: 'Directory not empty. Continue [force overwrite]?',
43
+ initial: false
44
+ }
45
+ }
46
+
47
+ if (fs.existsSync(cwd)) {
48
+ if (fs.readdirSync(cwd).length > 0) {
49
+ const { overwrite } = await prompts(questions.overwrite)
50
+ if (!overwrite) {
51
+ process.exit(1)
52
+ }
53
+ !current && mkdirp(cwd)
54
+ }
55
+ } else {
56
+ !current && mkdirp(cwd)
57
+ }
58
+
59
+ try {
60
+ log('copying project files...')
61
+
62
+ // Copy template files from the package
63
+ const templateDir = path.join(__dirname, '../template')
64
+ await fs.copy(templateDir, cwd, {
65
+ overwrite: true,
66
+ filter: src => {
67
+ // Skip node_modules and dist directories
68
+ return !src.includes('node_modules') && !src.includes('dist')
69
+ }
70
+ })
71
+
72
+ // Update package.json with project name
73
+ const pkgPath = path.join(cwd, 'package.json')
74
+ if (fs.existsSync(pkgPath)) {
75
+ const pkg = await fs.readJson(pkgPath)
76
+ pkg.name = projectName
77
+ await fs.writeJson(pkgPath, pkg, { spaces: 2 })
78
+ }
79
+ } catch (err) {
80
+ console.error(`${pc.cyan(pc.bold('CREATE-PUGKIT'))} ${pc.dim(`v${pkgVersion()}`)} ${pc.red(err.message)}`)
81
+ process.exit(1)
82
+ }
83
+
84
+ log('done!')
85
+ console.log('\nNext steps:')
86
+
87
+ let step = 1
88
+
89
+ const relative = path.relative(process.cwd(), cwd)
90
+ if (relative !== '') {
91
+ console.log(` ${step++}: ${pc.bold(pc.cyan(`cd ${relative}`))}`)
92
+ }
93
+
94
+ console.log(` ${step++}: ${pc.bold(pc.cyan('npm install'))}`)
95
+ console.log(` ${step++}: ${pc.bold(pc.cyan('npm run build'))}`)
96
+ console.log(` ${step++}: ${pc.bold(pc.cyan('npm run dev'))}`)
97
+ console.log(`\nTo close the dev server, hit ${pc.bold(pc.cyan('Ctrl + C'))}`)
98
+ }
99
+
100
+ const cli = cac('create-pugkit')
101
+
102
+ cli.command('[root]', 'Scaffolding for pugkit projects').action(async (root, options) => {
103
+ try {
104
+ await main(root, options)
105
+ } catch (err) {
106
+ console.error(err)
107
+ process.exit(1)
108
+ }
109
+ })
110
+
111
+ cli.help()
112
+ cli.version(pkgVersion())
113
+ cli.parse()
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "create-pugkit",
3
+ "version": "1.0.0-beta.1",
4
+ "description": "Scaffolding for pugkit projects",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "mfxgu2i <mfxgu2i@gmail.com>",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/mfxgu2i/pugkit.git",
11
+ "directory": "packages/create-pugkit"
12
+ },
13
+ "bugs": "https://github.com/mfxgu2i/pugkit/issues",
14
+ "homepage": "https://github.com/mfxgu2i/pugkit#readme",
15
+ "publishConfig": {
16
+ "access": "public"
17
+ },
18
+ "bin": {
19
+ "create-pugkit": "./cli/index.mjs"
20
+ },
21
+ "files": [
22
+ "cli",
23
+ "template"
24
+ ],
25
+ "keywords": [
26
+ "pugkit",
27
+ "pug",
28
+ "sass",
29
+ "static-site-generator",
30
+ "scaffold"
31
+ ],
32
+ "dependencies": {
33
+ "cac": "^6.7.14",
34
+ "fs-extra": "^11.2.0",
35
+ "picocolors": "^1.1.1",
36
+ "prompts": "^2.4.2"
37
+ },
38
+ "devDependencies": {
39
+ "@types/fs-extra": "^11.0.4",
40
+ "@types/prompts": "^2.4.9"
41
+ },
42
+ "engines": {
43
+ "node": ">=18.0.0"
44
+ }
45
+ }
@@ -0,0 +1,20 @@
1
+ # Browsers that we support
2
+
3
+ # Windows 10 and later
4
+
5
+ last 2 Edge versions
6
+ last 2 Chrome versions
7
+
8
+ # MAC with the latest Mac OS
9
+
10
+ last 2 Safari versions
11
+
12
+ # Android 11 and later
13
+
14
+ last 2 ChromeAndroid versions
15
+
16
+ # iPhone with the latest iOS
17
+
18
+ last 2 iOS versions
19
+
20
+ not dead
@@ -0,0 +1,48 @@
1
+ export default {
2
+ // ========================================
3
+ // 基本設定
4
+ // ========================================
5
+
6
+ // 1行の最大文字数
7
+ printWidth: 120,
8
+
9
+ // インデント幅
10
+ tabWidth: 2,
11
+
12
+ // タブを使用しない(スペース推奨)
13
+ useTabs: false,
14
+
15
+ // セミコロンなし
16
+ semi: false,
17
+
18
+ // シングルクォート優先
19
+ singleQuote: true,
20
+
21
+ // オブジェクトリテラルの括弧内にスペース
22
+ bracketSpacing: true,
23
+
24
+ // 末尾カンマなし
25
+ trailingComma: 'none',
26
+
27
+ // アロー関数の括弧(必要時のみ)
28
+ arrowParens: 'avoid',
29
+
30
+ // 改行コード(LF統一)
31
+ endOfLine: 'lf',
32
+
33
+ // ========================================
34
+ // ファイル別設定
35
+ // ========================================
36
+
37
+ overrides: [
38
+ // CSS / SCSS(ダブルクォート統一)
39
+ {
40
+ files: '*.{css,scss}',
41
+ options: {
42
+ singleQuote: true,
43
+ printWidth: 120,
44
+ tabWidth: 2
45
+ }
46
+ }
47
+ ]
48
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "test-project",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "pugkit dev",
8
+ "build": "pugkit build",
9
+ "sprite": "pugkit sprite",
10
+ "lint": "npm run lint:js && npm run lint:scss",
11
+ "lint:js": "eslint 'src/**/*.js'",
12
+ "lint:scss": "stylelint 'src/**/*.scss'",
13
+ "format": "npm run format:js && npm run format:scss",
14
+ "format:js": "prettier --write 'src/**/*.js'",
15
+ "format:scss": "stylelint 'src/**/*.scss' --fix"
16
+ },
17
+ "devDependencies": {
18
+ "prettier": "^3.8.1",
19
+ "pugkit": "^1.0.0-beta.2",
20
+ "stylelint": "^16.12.0",
21
+ "stylelint-config-recess-order": "^5.1.1",
22
+ "stylelint-config-standard-scss": "^14.0.0"
23
+ }
24
+ }
@@ -0,0 +1,38 @@
1
+ import { defineConfig } from 'pugkit'
2
+
3
+ // See: https://github.com/mfxgu2i/pugkit#configuration
4
+ export default defineConfig({
5
+ siteUrl: 'https://example.com/',
6
+ subdir: '',
7
+ debug: false,
8
+ server: {
9
+ port: 5555,
10
+ host: 'localhost',
11
+ startPath: '/'
12
+ },
13
+ build: {
14
+ imageOptimization: 'webp',
15
+ imageOptions: {
16
+ webp: {
17
+ quality: 90,
18
+ effort: 6,
19
+ smartSubsample: true,
20
+ method: 6,
21
+ reductionEffort: 6,
22
+ alphaQuality: 100,
23
+ lossless: false
24
+ },
25
+ jpeg: {
26
+ quality: 75,
27
+ progressive: true,
28
+ mozjpeg: false
29
+ },
30
+ png: {
31
+ quality: 85,
32
+ compressionLevel: 6,
33
+ adaptiveFiltering: true,
34
+ palette: true
35
+ }
36
+ }
37
+ }
38
+ })
@@ -0,0 +1,14 @@
1
+ -
2
+ const META_DATA = {
3
+ siteTitle: 'pugkit',
4
+ siteDescription: '__サイトの説明__',
5
+ pageTitle: '__ページタイトル__',
6
+ pageDescription: '__ページの説明__',
7
+ pageType: 'article'
8
+ }
9
+
10
+ const BREAK_POINTS = {
11
+ sm: '(max-width: 575px)',
12
+ md: '(max-width: 767.98px)',
13
+ lg: '(max-width: 889.98px)',
14
+ }
@@ -0,0 +1,42 @@
1
+ include /_templates/_constants
2
+ include /_templates/mixins/_Meta
3
+ include /_templates/mixins/_Image
4
+
5
+ block vars
6
+ - const metaData = META_DATA
7
+
8
+ doctype html
9
+ html(lang='ja')
10
+ head
11
+ +Meta(metaData)
12
+
13
+ //- 計測タグ
14
+ block analytics
15
+
16
+ //- 構造化データ
17
+ block structuredData
18
+
19
+ //- 外部リソース
20
+ block externalResources
21
+
22
+ //- サイトリソース
23
+ block styles
24
+ link(rel='stylesheet' href=`${Builder.dir}assets/css/style.css`)
25
+
26
+ block scripts
27
+ script(src=`${Builder.dir}assets/js/main.js` type='module')
28
+
29
+ body
30
+ block bodyAnalytics
31
+
32
+ //- ヘッダー
33
+ block header
34
+ include /_templates/components/_header
35
+
36
+ //- コンテンツ
37
+ main
38
+ block contents
39
+
40
+ //- フッター
41
+ block footer
42
+ include /_templates/components/_footer
@@ -0,0 +1,2 @@
1
+ footer.c-footer
2
+ p.c-footer__copyright
@@ -0,0 +1,9 @@
1
+ header.c-header
2
+ #{Builder.url.pathname === '/' ? 'h1' : 'div'}.c-header__logo
3
+ a.c-header__logo-link(href=Builder.dir)= metaData.siteTitle
4
+ nav.c-header__nav
5
+ ul.c-header__nav-list
6
+ li.c-header__nav-item
7
+ a.c-header__nav-link(href=Builder.dir) Home
8
+ li.c-header__nav-item
9
+ a.c-header__nav-link(href=`${Builder.dir}about/`) About
@@ -0,0 +1,103 @@
1
+ //- ============================================================
2
+ //- Image mixin
3
+ //- ============================================================
4
+ //- 引数
5
+ //- path {string} img/ 以下の画像パス(必須)
6
+ //- args {object} オプション
7
+ //- alt {string} 代替テキスト(デフォルト: '')
8
+ //- lazy {boolean} 遅延読み込み(デフォルト: true)
9
+ //- webp {boolean} WebP source を出力するか(デフォルト: true)
10
+ //- class {string} picture 要素のクラス
11
+
12
+ //- 使用例
13
+ //- +Image('hero.jpg')
14
+ //- +Image('hero.jpg', { alt: 'ヒーロー画像', lazy: false })
15
+ mixin Image(path, args = {})
16
+ -
17
+ const src = `${Builder.dir}assets/img/${path}`;
18
+ const ext = src.slice(src.lastIndexOf('.'));
19
+ const isSvg = ext === '.svg';
20
+
21
+ const base = src.substring(0, src.lastIndexOf('.'));
22
+ const webpPath = `${base}.webp`;
23
+ const retinaWebp = `${base}@2x.webp 2x`;
24
+
25
+ const alt = args.alt || '';
26
+ const loading = args.lazy !== false ? 'lazy' : undefined;
27
+ const fetchpriority = args.lazy === false ? 'high' : undefined;
28
+ const width = imageSize(src).width;
29
+ const height = imageSize(src).height;
30
+
31
+ // SVG は retina 不要のため 1x のみ。ラスター画像は 1x + 2x
32
+ const webpSrcset = isSvg ? webpPath : `${webpPath} 1x, ${retinaWebp}`;
33
+
34
+ picture(class=args.class)
35
+ if !isSvg && args.webp !== false
36
+ source(type='image/webp' srcset=webpSrcset)
37
+ img(
38
+ src=isSvg ? src : webpPath
39
+ alt=alt
40
+ width=width
41
+ height=height
42
+ loading=loading
43
+ fetchpriority=fetchpriority
44
+ )
45
+
46
+ //- ============================================================
47
+ //- ResponsiveImage mixin — レスポンシブ対応画像
48
+ //- ============================================================
49
+ //- 引数 ※ SVG は非対応。ラスター画像(jpg / png / webp 等)のみ使用可
50
+ //- path {string} img/ 以下の画像パス(必須)。SP 画像は `basename_sp.ext` を自動参照
51
+ //- args {object} オプション
52
+ //- alt {string} 代替テキスト(デフォルト: '')
53
+ //- media {string} SP 用ブレークポイントキー 'sm' | 'md' | 'lg'(デフォルト: 'md')
54
+ //- lazy {boolean} 遅延読み込み(デフォルト: true)
55
+ //- webp {boolean} WebP source を出力するか(デフォルト: true)
56
+ //- class {string} picture 要素のクラス
57
+
58
+ //- 使用例
59
+ //- +ResponsiveImage('hero.jpg')
60
+ //- +ResponsiveImage('hero.jpg', { media: 'sm', alt: 'ヒーロー画像' })
61
+ mixin ResponsiveImage(path, args = {})
62
+ -
63
+ const src = `${Builder.dir}assets/img/${path}`;
64
+ const ext = src.slice(src.lastIndexOf('.'));
65
+
66
+ const base = src.substring(0, src.lastIndexOf('.'));
67
+ const webpPath = `${base}.webp`;
68
+ const retinaWebp = `${base}@2x.webp 2x`;
69
+ const spWebp = `${base}_sp.webp`;
70
+ const spPath = `${base}_sp${ext}`;
71
+
72
+ const alt = args.alt || '';
73
+ const media = BREAK_POINTS[args.media] || BREAK_POINTS.md;
74
+ const loading = args.lazy !== false ? 'lazy' : undefined;
75
+ const fetchpriority = args.lazy === false ? 'high' : undefined;
76
+ const webpSrcset = `${webpPath} 1x, ${retinaWebp}`;
77
+
78
+ const width = imageSize(src).width;
79
+ const height = imageSize(src).height;
80
+ const spWidth = imageSize(spPath).width;
81
+ const spHeight = imageSize(spPath).height;
82
+
83
+ picture(class=args.class)
84
+ //- SP 用 source(メディアクエリ付き)
85
+ if args.webp !== false
86
+ source(
87
+ type='image/webp'
88
+ media=media
89
+ srcset=spWebp
90
+ width=spWidth
91
+ height=spHeight
92
+ )
93
+ //- PC 用 source
94
+ if args.webp !== false
95
+ source(type='image/webp' srcset=webpSrcset)
96
+ img(
97
+ src=webpPath
98
+ alt=alt
99
+ width=width
100
+ height=height
101
+ loading=loading
102
+ fetchpriority=fetchpriority
103
+ )
@@ -0,0 +1,38 @@
1
+ mixin Meta(meta = {})
2
+ -
3
+ const site = {
4
+ title: meta.siteTitle || '__サイトタイトル__',
5
+ description: meta.siteDescription || '__サイト説明文__',
6
+ }
7
+
8
+ const page = {
9
+ title: meta.pageTitle || '',
10
+ description: meta.pageDescription || '',
11
+ type: meta.pageType || 'article'
12
+ }
13
+
14
+ const title = Builder.pathname === '/' || !page.title ? site.title : `${page.title}|${site.title}`
15
+ const description = page.description || site.description
16
+ const ogImage = `${Builder.url.base}/assets/img/common/ogp.jpg`
17
+
18
+ //- 基本メタ情報
19
+ meta(charset='UTF-8')
20
+ meta(name='viewport' content='width=device-width,initial-scale=1,viewport-fit=cover')
21
+ meta(name='format-detection' content='telephone=no')
22
+ meta(name='mobile-web-app-capable' content='yes')
23
+
24
+ //- アイコン
25
+ link(rel='icon' href='/favicon.ico')
26
+
27
+ //- タイトルと説明
28
+ title !{title}
29
+ meta(name='description' content=description)
30
+
31
+ //- OGP
32
+ meta(property='og:title' content!=title)
33
+ meta(property='og:url' content=Builder.url.href)
34
+ meta(property='og:description' content=description)
35
+ meta(property='og:type' content=page.type)
36
+ meta(property='og:image' content=ogImage)
37
+ meta(property='og:site_name' content=site.title)
38
+ meta(name='twitter:card' content='summary_large_image')
@@ -0,0 +1,26 @@
1
+
2
+ extends /_templates/_layout
3
+
4
+ block append vars
5
+ -
6
+ metaData.pageTitle = 'About'
7
+ metaData.pageDescription = ''
8
+ metaData.pageType = 'article'
9
+
10
+ block contents
11
+ section.page
12
+ .page__inner
13
+ h2.page__title About
14
+ .page__content
15
+ p.page__text pugkitは静的サイト制作に特化したビルドツールです。PugテンプレートとSassを中心としたシンプルな構成で、納品向きの綺麗なHTMLと、構成に制約のないアセット出力が可能です。
16
+ h3.page__heading Tech Stack
17
+ ul.page__list
18
+ li.page__list-item Pug — HTMLテンプレートエンジン
19
+ li.page__list-item Sass — CSSプリプロセッサー
20
+ li.page__list-item esbuild — TypeScript / JavaScriptバンドラー
21
+ li.page__list-item Sharp — 画像最適化(WebP変換)
22
+ h3.page__heading Quick Start
23
+ pre.page__code.
24
+ npm create pugkit@latest
25
+ .page__buttons
26
+ a.page__button(href=Builder.dir) トップに戻る