ついにIEのサポートが終了したので、更新しました。
Web制作向けnpm-scripts 2
Web制作向けnpm-scripts
変更点
- IE対応廃止(JSのバンドル、polyfili自動追加、トランスパイル)
- webp対応(JPG、PNGもwebpに変換)
- ESModule化
補足
- node.js v18.7.0、npm 7.7.4で作成
- avif対応は時期尚早のため見送り
ファイル構成
website
├ src
│ ├ pug
│ ├ img
│ ├ scss
│ └ ts
├ package.json
├ package-lock.json
├ imagemin.js
├ jest.config.js
├ tsconfig.json
├ .browserslistrc
├ .eslintrc.json
├ .prettierrc.json
├ .stylelintrc.json
└ .stylelintignore
npm-scriptsの準備
npm init -y
npm i -D npm-run-all
npm i -D chokidar-cli
ホットリロード
Browser-Sync
インストール
npm i -D browser-sync
npmコマンド追加
"scripts": {
"start:server": "browser-sync start -s dist -w src/*.html src/css/*.css src/js/*.js"
}
動作確認
npm run start:server
ブラウザが立ち上がれば成功です。
まだデータが無いのでエラーで問題ありません。
Ctrl+Cで終了します。
Pug
インストール
npm i -D github:pugjs/pug-cli#master
npmコマンド追加
"scripts": {
"compile:pug": "pug src/pug/ --hierarchy -o dist/ -P",
"watch:pug": "pug src/pug/ --hierarchy -o dist/ -w -P",
}
動作確認
/src/pug/配下にPugファイルを設置して、変換してみてください。
Pugの記法まとめ
//1回変換
npm run compile:pug
//Pugファイルの変更を監視して変換
npm run watch:pug
/src/pug/配下のPugファイルが/dist/配下にHTMLとして変換されれば成功です。
CSS
Sass(Dart-Sass)
SCSSファイルをCSSファイルに変換します。
インストール
npm i -D sass
autoprefixer
CSSのプロパティにベンダープレフィックスを付与します。
インストール]
npm i -D postcss-cli
npm i -D autoprefixer
npm i -D postcss
対象ブラウザの指定
設定例
defaults
設定は下記URLを参考に適宜変更してください。
browserslist
対象ブラウザの確認
npx browserslist
npmコマンド追加
"scripts": {
"compile:css2cssprefix": "postcss dist/css/style.css -u autoprefixer -o dist/css/style.css",
"compile:scss2css": "sass src/scss/style.scss:dist/css/style.css --style=expanded --source-map-urls=relative",
"compile:scss2cssprefix": "run-s compile:scss2css compile:css2cssprefix",
"watch:scss2cssprefix": "chokidar \"src/scss/\" --command \"npm run compile:scss2cssprefix\" --initial",
}
動作確認
/src/scss/配下にSCSSファイルを設置して、変換してみてください。
//SCSSファイルをベンダープレフィックス付きでCSSに変換(1回)
npm run compile:scss2cssprefix
//SCSSファイルをベンダープレフィックス付きでCSSに変換(SCSSファイルを監視して変更される度)
npm run watch:scss2cssprefix
/src/scss/配下のSCSSファイルが/dist/css/配下にCSSファイルとして変換されれば成功です。
TypeScript
JavaScriptへの変換を行います。
インストール
npm i -D typescript
設定ファイルの準備
tsconfig.jsonを作成します。
tsc --init
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "ESNEXT" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
"module": "ESnext" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
// "lib": [], /* Specify library files to be included in the compilation. */
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
"sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "./dist/js" /* Redirect output structure to the directory. */,
"rootDir": "./src/ts" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */,
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": true /* Enable all strict type-checking options. */,
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
// "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
/* Advanced Options */
"skipLibCheck": true /* Skip type checking of declaration files. */,
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
},
"exclude": ["node_modules"]
}
動作確認
import { importTest } from "./sub";
const message = "TypeScriptの変換成功";
console.log(message);
console.log(importTest);
export const importTest: string = "sub.tsからのimport成功";
//TypeScriptファイルをJavsScriptファイルに変換
npm run compile:ts
//TypeScriptファイルをJavsScriptファイルに変換(TypeScriptファイルを監視して変更される度)
npm run watch:ts
/src/ts/配下のTypeScriptファイルが/dist/js/配下にJavsScriptファイルとして変換されれば成功です。
画像圧縮
対応するファイル形式
- jpg
- png
- webp
- gif
- svg
(jpgとpngはwebpに変換します)
インストール
npm i -D imagemin-cli
npm i -D imagemin-keep-folder
npm i -D imagemin-gifsicle
npm i -D imagemin-svgo
npm i -D imagemin-webp
npmコマンド追加
"scripts": {
"watch:img": "chokidar \"src/img/**/*\" --command \"node imagemin.js\" --initial"
}
設定ファイル
import keepfolder from "imagemin-keep-folder";
import gifsicle from "imagemin-gifsicle";
import svgo from "imagemin-svgo";
import webp from "imagemin-webp";
keepfolder(["src/img/**/*.{jpg,png,gif,svg,webp}"], {
plugins: [
gifsicle(),
svgo(),
webp({
quality: 50,
}),
],
replaceOutputDir: (output) => {
return output.replace(/img\//, "../dist/img/");
},
});
//追加
"type": "module",
動作確認
/src/img/配下に画像を格納します。(jpg、png、gif、svg、webp)
npm run watch:img
/src/img/配下の画像が圧縮されて/dist/img/配下にコピーされれば成功です。
distディレクトリの削除
以前の作業で生成したファイルがdistに残っているとトラブルにつながる恐れがあるため、削除します。
インストール
npm i rimraf -D
npmコマンド追加
"scripts": {
"delete:dist": "rimraf dist"
}
動作確認
npm run delete:dist
distディレクトリが削除されれば成功です。
ファイルのコピー
今回は、sitemap.xml、robots.txt、humans.txt、manifest.json、favicon.ico、apple-touch-icon.pngをコピーするようにします。
あまり変更が入らないファイルのコピーを想定しているので、-w オプションは付けません。
インストール
npm i -D cpx
npmコマンド追加
"scripts": {
"copy:sitemapxml": "cpx \"src/sitemap.xml\" dist/",
"copy:robotstxt": "cpx \"src/robots.txt\" dist/",
"copy:humanstxt": "cpx \"src/humans.txt\" dist/",
"copy:manifestjson": "cpx \"src/manifest.json\" dist/",
"copy:faviconico": "cpx \"src/favicon.ico\" dist/",
"copy:apple-touch-iconpng": "cpx \"src/apple-touch-icon.png\" dist/"
}
動作確認
npm run copy:sitemapxml
/src/sitemap.xmlが/dist/sitemap.xmlにコピーされれば成功です。
タスクの連携
これまで作ってきたタスクを連携して、コマンド1つで実行できるようにします。
npmコマンドの追加
"scripts": {
"prewatch:all": "run-s delete:dist copy:sitemapxml copy:robotstxt copy:humanstxt copy:manifestjson copy:faviconico copy:apple-touch-iconpng",
"watch:all": "run-p watch:pug watch:scss2cssprefix watch:ts watch:img start:server"
}
動作確認
npm run watch:all
HTML、CSS、JavaScriptのコンパイルを並列処理しているので、表示が崩れている場合は完了タイミングが異なっているのが原因と思われますので、リロードしてみてください。
コード整形
prettier
インストール
npm i -D prettier
{
"semi": true,
"trailingComma": "all",
"printWidth": 120,
"tabWidth": 2,
"useTabs": false,
"proseWrap": "preserve",
"endOfLine": "auto"
}
設定は下記URLを参考に適宜変更してください。
stylelint
インストール
npm i -D stylelint
npm i -D stylelint-config-recommended-scss
npm i -D stylelint-config-prettier
npm i -D stylelint-scss
npm i -D stylelint-order
npm i -D stylelint-prettier
npmコマンド追加
"scripts": {
"lint:scss": "stylelint \"**/*.scss\"",
"format:scss": "stylelint --fix \"**/*.scss\""
}
設定ファイル
{
"extends": [
"stylelint-config-recommended-scss",
"stylelint-config-prettier"
],
"plugins": [
"stylelint-order",
"stylelint-prettier"
],
"rules": {
"prettier/prettier": true,
"indentation": 2,
"declaration-colon-newline-after": null,
"value-list-comma-newline-after": "never-multi-line",
"order/properties-alphabetical-order": true
}
}
設定は下記URLを参考に適宜変更してください。
.stylelintrc
動作確認
//SCSSファイルのリント
npm run lint:scss
//SCSSファイルの整形
npm run format:scss
Eslint
インストール
npm i -D eslint
npm i -D @typescript-eslint/parser
npm i -D eslint-config-prettier
npmコマンド追加
"scripts": {
"lint:ts": "eslint src/ts/**/*.ts",
"format:ts": "eslint src/ts/**/*.ts --fix"
}
設定ファイル
envの設定値 | 内容 |
---|---|
"browser": true | 無いとdocumentやconsoleなどでエラーが出てしまう |
"node":true | 無いとwebpack.config.jsonのdirname、module、requireでエラーが出てしまう |
{
"parser": "@typescript-eslint/parser",
"extends": [
"eslint:recommended",
"prettier"
],
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"env": {
"browser": true,
"node": true
},
"root": true,
"rules": {
"quotes": ["error", "double"], //クォーテーションがシングルのときエラー
"indent": ["error", 2]
}
}
設定は下記URLを参考に適宜変更してください。
Configuring ESLint
動作確認
//TypeScriptファイルのリント
npm run lint:ts
//TypeScriptファイルの整形
npm run format:ts
SCSS、TypeScript一括整形
"scripts": {
"format:all":"run-p format:scss format:ts"
}
動作確認
//TypeScriptファイル、SCSSファイルの整形
npm run format:all
commit前にコード整形
インストール
npm i -D simple-git-hooks
npm i -D lint-staged
コマンド | 内容 |
---|---|
pre-commit | コミット前に実行 |
pre-push | プッシュ前に実行 |
"simple-git-hooks": {
"pre-commit": "npx lint-staged"
},
"lint-staged": {
"src/ts/*.ts": [
"prettier --write",
"eslint --fix --quiet"
],
"src/scss/*.scss": [
"prettier --write",
"stylelint --fix --quiet"
]
}
pre-commit、pre-pushの有効化
npx simple-git-hooks
git/hooks/pre-commit、.git/hooks/pre-pushというファイルが作られます。
git commitを行うと、lint-stagedに指定したコマンドが実行されます。
テスト
Jestを使えるようにします。
インストール
npm i -D jest
npm i -D ts-jest
npm i -D @types/jest
npmコマンド追加
"scripts": {
"test": "jest"
}
設定ファイル
export default {
roots: ["<rootDir>/src/ts/"],
testMatch: ["**/__tests__/**/*.+(ts|tsx|js)", "**/?(*.)+(spec|test).+(ts|tsx|js)"],
transform: {
"^.+\\.(ts|tsx)$": "ts-jest",
},
};
eslintrc.jsonの変更
Eslintでテストコードにエラーが出ないように、jestを追加
"env": {
"browser": true,
"node":true,
"jest": true
},
コードのサンプル
テスト用サンプルコード
export const calc = (x: number, y: number) => {
return x + y;
}
テストコード
import { calc } from "../test_for_jest";
describe("関数calcの動作確認", () => {
it("3+4=7になる", () => {
expect(calc(1, 8)).toBe(9);
});
});
.spec.tsを変換しないようにtsconfigの設定変更
"exclude": ["node_modules"]
↓
"exclude": ["node_modules", "**/*.spec.ts"]
動作確認
npm run test
本番公開対応
/dist/配下のCSS、JavaScriptのminifyを行います。
インストール
npm i -D uglify-es
npm i -D clean-css-cli
npmコマンド追加
"scripts": {
"min:css":"cleancss -o dist/css/style.css dist/css/style.css",
"min:js": "uglifyjs dist/js/main.js -o dist/js/main.js",
"prepare:all":"run-p min:js min:css"
}
動作確認
npm run prepare:all
/dist/配下のファイルをアップロードします
まとめ
使用時準備
git clone https://github.com/takeshisakuma/testament.git
cd testament
npm ci
npx simple-git-hooks
制作時
npm run watch:all
コード整形時
npm run format:all
テスト
npm run test
minify
npm run prepare:all
dist配下のファイルをそのままアップロードします
リポジトリ