いままで、HTMLの生成はpugを使用していたのですが、
このご時世、そろそろ他にいいものがあるのでは…?
と調べてみたところ、今更ながらAstroを知ったので、さっそく案件に取り入れてみた記録
極力生成されたソースにAstroで作ったという痕跡を残してほしくないということで、
デフォルトと異なる設定にした場所中心の備忘となります。
node -v 22.13.1
npm -v 10.9.2
astro@5.2.5
での内容です
要件
- APIなどのつなぎ込みのない、HMTLとCSSとJSで静的なモックを作成する
- 生成したHTMLを直接ブラウザで閲覧出来るようにする
- 相対パスでパス指定する
- IE11は非対応でOK
HTML関連
インデント有にしてほしい
とのことだったので、astro.config
にてインデントありの設定に変更
compressHTML: false,
(公式)
結果、生成されたHTMLはインデントがついてはいる。が、結構ぐちゃぐちゃでした。
なので、astroでビルド→prettierで整形という処理をbuild時に実行するように修正。
prettierは最大80文字と、空白処理をコマンドで上書き
(--print-width 1000 --html-whitespace-sensitivity ignore
)
(一応)先方の納得のいく形になりました。
改行コードはCRLFにしたい
Astroでbuildをしたソースは、LFになるようです。
ビルド後のソースの改行コード変更に関するconfigの設定は公式でなさそう…
CRLFに変更という処理を自前で設定(node convertLine.cjs)
こちらも、build時にastroでビルド→LFをCRLFに変更という処理を自前で追加しました
convertLine.cjs
const fs = require('fs');
const path = require('path');
// 設定(対象フォルダ & 拡張子)
const targetDir = './dist'; // 変換したいフォルダのパス
const extensions = ['.html', '.css', '.js']; // 変換対象の拡張子リスト
// 再帰的にフォルダ内のファイルを処理
function convertLineEndings(dir) {
fs.readdirSync(dir, { withFileTypes: true }).forEach((entry) => {
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory()) {
// サブフォルダがあれば再帰処理
convertLineEndings(fullPath);
} else if (extensions.includes(path.extname(entry.name))) {
// 指定の拡張子に一致するファイルを変換
const content = fs.readFileSync(fullPath, 'utf8');
// 改行を CRLF に統一
const convertedContent = content.replace(/\r?\n/g, '\r\n');
fs.writeFileSync(fullPath, convertedContent, 'utf8');
}
});
}
// 実行
convertLineEndings(targetDir);
相対パス指定
公式では相対パス指定は対応していないそうです。
「Astro 相対パス」などでググったらでてきます。
以下のパッケージを使用させていただきました。
astro-relative-links
CSS関連
スコープ対応しないでほしい
…お客さんの要望なら聞くしかありません。
.astro内に<style>
タグを記述するのがAstroでは一般的など思われます。
その場合、<style is:global>
とすると、スコープ対応されないようです。
公式:グローバルスタイル
外部のCSS(node_modules)や、そのほか作成したCSSやSCSSなどは
スクリプトの先頭にimportで読み込みを追加すればOKです
ex
---
import '@/assets/style/style.scss'
---
dev開発時の<style is:global>
- devで開発中はバッティングしていなかったのに、ビルドしたらCSSがバッティングしてしまう
- 別ファイルでis:globalにしたはずなのに、Styleが当たらない
ということが度々ありました。
dev開発時はグローバル指定が反映されない?ようです。
別ファイルでCSSにしてほしい
こちらもデフォルトだと、ビルド後は.cssファイルが出来上がるのではなくhead
内にstyleタグでの追加となるようです。
公式に設定の変更方法がありました:build.inlineStylesheets
ということで、上記を参考にastro.configに以下を追記しました。
export default defineConfig({
build: {
inlineStylesheets: 'never',
assets: 'assets',
}
})
上記設定をすると、head
内CSSがdist/assets/XXXX.css
というディレクトリに生成されます。
ここで新たな問題が発生です
別ファイルにしたCSSを指定の場所に格納したい
dist/assets/XXXX.css
ではなく、dist/assets/style/XXXX.css
に変更したい。
上記設定のbuild.assets: 'assets'
をassets/style
に変更すれば解決します。
が、画像も同様にassets => assets/style
となってしまうのです。
なので、viteのbuild設定にて、assets配下のファイル格納先を変更するように追記しました。
astro.config.mjs
import { defineConfig } from "astro/config";
export default defineConfig({
build: {
inlineStylesheets: 'never',
assets: 'assets',
},
vite: {
build: {
rollupOptions: {
output: {// ★★以下を追記★★
assetFileNames: (assetInfo) => {
let extType = assetInfo.names[0].split('.').at(-1);
if (extType && /png|jpe?g|svg|gif|webp|ico/i.test(extType)) extType = 'img';
if (extType && /css|scss/i.test(extType)) extType = 'css';
return `assets/${extType}/[name][extname]`;
},
},
},
},
},
});
別ファイルにしたCSSを1つにまとめてほしい
どんどん実装していくと、CSSが増え、生成されたファイルが長くなります。
すると、生成されたCSSが分割されるようになりました。
原因はたぶん、Astroが使用してるviteのデフォルトでCSSコード分割が有効になっているからっぽいです。
https://ja.vite.dev/config/build-options.html#build-csscodesplit
こちらを無効にし、かつ、インライン記述するMAX値も0としておきます。
export default defineConfig({
vite: {
build: {
rollupOptions: {
assetsInlineLimit: 0, ★
cssCodeSplit: false, ★
JS関連
scriptの読み込みをtype="module"
ではなくしたい
ビルドされたファイルのscript読み込みはtype="module"
での読み込みとなるようです。
これが直接ブラウザでみるとCORSのエラーになるようでした。
つまり、公式のように
.astroに<script>~<script>
でもNG。
sciptタグでの読み込みもNG。
ファイル内の先頭にimportしてもNG。
となると、publicに.jsを作って、そこを外部JSとして読み込むようにするしかない…
という結論になりました。(もしかしたら他にいい方法があったのかも。)
なので、AstroでのJSビルドは行わず、rollupで別途ビルドするように設定ファイルを作成
ローカル開発時はpublic/assets/js/script.js
が出来上がるように設定
ビルド時はdist/assets/js/script.js
が出来上がるように設定
としました
rollup.config.js
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import terser from '@rollup/plugin-terser';
import watcher from 'rollup-plugin-watcher';
const srcDir = './src/assets/js/';
const publicDir = './public/assets/js/';
const distDir = './dist/assets/js/';
const isProduction = process.env.NODE_ENV === 'prod';
const pluginOptsion = [
resolve(),
commonjs({
sourceMap: false,
}),
isProduction &&
terser({
compress: {
drop_console: true,
drop_debugger: true,
},
}),
!isProduction && watcher(['src/assets/**/**.js']),
];
const watchOption = isProduction
? false
: {
include: 'src/assets/**/**.js',
chokidar: {
usePolling: false,
},
};
const config = [
{
input: `${srcDir}AAA.js`,
output: {
file: isProduction ? `${distDir}mock.js` : `${publicDir}mock.js`,
format: 'iife',
name: 'AAA',
sourcemap: !isProduction,
},
watch: watchOption,
plugins: pluginOptsion,
},
];
export default config;
asset関連
src配下に複数のディレクトリに分けて画像を格納し、astroのImage
で読み込むと、
distの中に生成されるときは全て1階層になります
src/assets/images/common/icon.png => dist/assetes/images/icon.png
distでもディレクトリ構造を保ったままにしたい場合、
public内に画像を格納し、Imageでの読み込みではなく普通にimgタグとして読み込むようにすればディレクトリを保ったままbuildができます。
Imageを使う&&ディレクトリ構造を保つ。というのは実現が難しいためどちらかしかできません。
という内容で相談のうえ、今回はImageを使用し、distの中は1階層になるで譲歩いただきました。
最終config
astro.config.mjs
import relativeLinks from 'astro-relative-links';
import { defineConfig } from 'astro/config';
import autoprefixer from 'autoprefixer';
import path, { dirname } from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// https://astro.build/config
export default defineConfig({
server: {
open: true,
},
compressHTML: true,
integrations: [relativeLinks()],
build: {
format: 'file',
inlineStylesheets: 'never',
assets: 'assets',
},
vite: {
resolve: {
alias: {
'@/': `${path.resolve(__dirname, 'src')}/`,
},
},
build: {
assetsInlineLimit: 1,
cssCodeSplit: false,
rollupOptions: {
output: {
// entryFileNames: `assets/js/script.js`,
manualChunks: undefined,
assetFileNames: (assetInfo) => {
let extType = assetInfo.names[0].split('.').at(-1);
if (extType && /png|jpe?g|svg|gif|tiff|webp|ico/i.test(extType)) {
extType = 'img';
}
if (extType && /css|scss/i.test(extType)) {
extType = 'css';
}
return `assets/${extType}/[name][extname]`;
},
},
},
},
css: {
preprocessorOptions: {
scss: {
// see: https://vite.dev/config/shared-options.html#css-preprocessoroptions
api: 'modern',
},
},
postcss: {
plugins: [autoprefixer()],
},
},
},
});
感想
これからは、静的なHTMLの作成とか、ちょっとしたサイトの作成など
全然Astro使っていきたいなと思いました…!