13
8

More than 1 year has passed since last update.

Web制作向けnpm-scripts 2

Last updated at Posted at 2021-04-08

更新版
Web制作向けnpm-scripts 3

変更点

  • EJS、Stylusは対応しない
  • webpackによるJavaScriptのバンドル対応
  • node-sassからDart-Sassに変更
  • Jest導入
  • コミット前のコードのリント、整形

補足

  • node-sassではglobを使っていたのですが、Dart-Sassではnpm-scriptsでglobを使う方法が不明なので対応していません
  • webpackの使用は最小限(JavaScriptのバンドル)に絞って使用するようにしています

フォルダ構成

directory
website
 ├ src
 │ ├ pug
 │ ├ img
 │ ├ scss
 │ └ ts
 ├ package.json
 ├ package-lock.json
 ├ imagemin.js
 ├ jest.config.js
 ├ tsconfig.json
 ├ webpack.config.js
 ├ .browserslistrc
 ├ .eslintrc.json 
 ├ .prettierrc.json 
 ├ .stylelintrc.json
 └ .stylelintignore 

npm-scriptsの準備

terminal
npm init -y

npm i -D npm-run-all
npm i -D chokidar-cli

ホットリロード

Browser-Sync

インストール

termina
npm i -D browser-sync

//IE11は2.25.0以降エラーになるので、IEでもbrowser-syncを使う場合は下記
npm i -D browser-sync@2.24.7

npmコマンド追加

package.json
"scripts": {
 "start:server": "browser-sync start -s dist -w src/*.html src/css/*.css src/js/*.js"
}

動作確認

terminal
npm run start:server 

ブラウザが立ち上がれば成功です。
まだデータが無いのでエラーで問題ありません。
Ctrl+Cで終了します。

Pug

インストール

terminal
npm i -D github:pugjs/pug-cli#master

npmコマンド追加

package.json
"scripts": {
  "compile:pug": "pug src/pug/ --hierarchy -o dist/ -P",
  "watch:pug": "pug src/pug/ --hierarchy -o dist/ -w -P",
}

動作確認

/src/pug/配下にPugファイルを設置して、変換してみてください。

Pugの記法まとめ

terminal
//1回変換
npm run compile:pug
 
//Pugファイルの変更を監視して変換
npm run watch:pug

/src/pug/配下のPugファイルが/dist/配下にHTMLとして変換されれば成功です。

Sass(Dart-Sass)

SCSSファイルをCSSファイルに変換します。

インストール

terminal
npm i -D sass

autoprefixer

CSSのプロパティにベンダープレフィックスを付与します。

インストール

terminal
npm i -D postcss-cli
npm i -D autoprefixer
npm i -D postcss

対象ブラウザの指定

設定例

.browserslistrc
defaults

設定は下記URLを参考に適宜変更してください。
https://github.com/browserslist/browserslist

.browserslistrcで対象ブラウザを指定する

.browserslistrcに設定した対象ブラウザの確認

対象ブラウザの確認

terminal
npx browserslist

npmコマンド追加

pacjage.json
"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ファイルを設置して、変換してみてください。
Sassの記法(SCSS構文)

terminal
//SCSSファイルをベンダープレフィックス付きでCSSに変換(1回)
npm run compile:scss2cssprefix

//SCSSファイルをベンダープレフィックス付きでCSSに変換(SCSSファイルを監視して変更される度)
npm run watch:scss2cssprefix

/src/scss/配下のSCSSファイルが/dist/css/配下にCSSファイルとして変換されれば成功です。

TypeScript

JavaScriptへの変換と、webpackによるバンドルを行います。

インストール

terminal
npm i -D typescript

npm i -D webpack
npm i -D webpack-cli
npm i -D ts-loader

npmコマンド追加

packege.json
"scripts": {
  "compile:ts": "webpack --mode production",
  "watch:ts": "webpack  --mode development --watch",
}

設定ファイル(TypeScript)

tsconfig.json
{
  "compilerOptions": {
    /* Basic Options */
    // "incremental": true,                   /* Enable incremental compilation */
    "target": "es5",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
    "module": "commonjs",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 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', or 'react'. */
    // "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": "./",                        /* Redirect output structure to the directory. */
    // "rootDir": "./",                       /* 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. */

    /* 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. */
  }
}

設定ファイル(webpack)

webpack.config.js
const path = require("path");

module.exports = {
    mode: "production",
    entry: "./src/ts/index.ts",

    output: {
        path: path.resolve(__dirname, "dist"),
        filename: "js/main.js",
    },

    devtool: "source-map",

    module: {
        rules: [
            {
                test: /\.ts$/,
                exclude: /node_modules/,
                use: "ts-loader",
            },
        ],
    },

    resolve: {
        extensions: [".ts", ".js", ".json"],
    },
};

動作確認

インポートした他のTypeScriptファイルが1つのJavsScriptファイルにバンドルされるのを確認します。

/src/ts/index.ts
import { importTest } from "./sub";

const message = "TypeScriptの変換成功";

console.log(message);
console.log(importTest);
/src/ts/sub.ts
export const importTest: string = "sub.tsからのimport成功";
terminal
//TypeScriptファイルをJavsScriptファイルに変換
npm run compile:ts

//TypeScriptファイルをJavsScriptファイルに変換(TypeScriptファイルを監視して変更される度)
npm run watch:ts

/src/ts/配下のTypeScriptファイルが/dist/js/配下にJavsScriptファイルとして変換されれば成功です。

画像圧縮

インストール

terminal
npm i -D imagemin-cli
npm i -D imagemin-keep-folder
npm i -D imagemin-mozjpeg
npm i -D imagemin-pngquant
npm i -D imagemin-gifsicle
npm i -D imagemin-svgo

npmコマンド追加

package.json
"scripts": {
  "watch:img": "chokidar \"src/img/**/*\" --command \"node imagemin.js\" --initial"
}

設定ファイル

imagemin.js
const keepfolder = require('imagemin-keep-folder');
const mozjpeg = require('imagemin-mozjpeg');
const pngquant = require('imagemin-pngquant');
const gifsicle = require('imagemin-gifsicle');
const svgo = require('imagemin-svgo');
 
keepfolder(['src/img/**/*.{jpg,png,gif,svg}'], {
  plugins: [
    mozjpeg({
      quality: 85
    }),
    pngquant({
      quality: [.7, .8]
    }),
    gifsicle(),
    svgo()
  ],
  replaceOutputDir: output => {
    return output.replace(/img\//, '../dist/img/')
  }
});

動作確認

/src/img/配下に画像を格納します。(jpg、png、gif、svg)

terminal
npm run watch:img

/src/img/配下の画像が圧縮されて/dist/img/配下にコピーされれば成功です。

distディレクトリの削除

以前の作業で生成したファイルがdistに残っているとトラブルにつながる恐れがあるため、削除します。

インストール

terminal
npm i rimraf -D

npmコマンド追加

package.json
"scripts": {
  "delete:dist": "rimraf dist"
}

動作確認

terminal
npm run delete:dist

distディレクトリが削除されれば成功です。

ファイルのコピー

今回は、sitemap.xml、robots.txt、humans.txt、manifest.json、favicon.ico、apple-touch-icon.pngをコピーするようにします。
あまり変更が入らないファイルのコピーを想定しているので、-w オプションは付けません。

インストール

terminal
npm i -D cpx

npmコマンド追加

package.json
"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/"
}

動作確認

terminal
npm run copy:sitemapxml

/src/sitemap.xmlが/dist/sitemap.xmlにコピーされれば成功です。

タスクの連携

これまで作ってきたタスクを連携して、コマンド1つで実行できるようにします。

package.json
"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"
}

動作確認

terminal
npm run watch:all

HTML、CSS、JavaScriptのコンパイルを並列処理しているので、表示が崩れている場合は完了タイミングが異なっているのが原因と思われますので、リロードしてみてください。

コード整形

prettier

インストール

terminal
npm i -D prettier 
.prettierrc.json
{
  "semi": true,
  "trailingComma": "all",
  "printWidth": 120,
  "tabWidth": 2,
  "useTabs": false,
  "proseWrap": "preserve",
  "endOfLine": "auto"
}

設定は下記URLを参考に適宜変更してください。
.prettierrc

stylelint

インストール

terminal
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コマンド追加

package.json
"scripts": {
  "lint:scss": "stylelint \"**/*.scss\"",
  "format:scss": "stylelint --fix \"**/*.scss\""
}

設定ファイル

.stylelintrc.json
{
  "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

動作確認

terminal
//SCSSファイルのリント
npm run lint:scss

//SCSSファイルの整形
npm run format:scss

Eslint

インストール

terminal
npm i -D eslint
npm i -D @typescript-eslint/parser
npm i -D eslint-config-prettier

npmコマンド追加

package.json
"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でエラーが出てしまう
.eslintrc.json
{
  "parser": "@typescript-eslint/parser",
  "extends": [
    "eslint:recommended",
    "prettier"
  ],
  "parserOptions":  {
    "ecmaVersion":  2020,
    "sourceType":  "module"
  },
  "env": {
    "browser": true,
    "node: true,
  },
  "root": true,
  "rules": {
    "quotes": ["error", "double"], //クォーテーションがシングルのときエラー
    "indent": ["error", 2]
  }
}

設定は下記URLを参考に適宜変更してください。
https://eslint.org/docs/user-guide/configuring

動作確認

terminal
//TypeScriptファイルのリント
npm run lint:ts
 
//TypeScriptファイルの整形
npm run format:ts

SCSS、TypeScript一括整形

package.json
"scripts": {
 "format:all":"run-p format:scss format:ts"
}

動作確認

terminal
//TypeScriptファイル、SCSSファイルの整形
npm run format:all

commit前にコード整形

インストール

terminal
npm i -D simple-git-hooks
npm i -D lint-staged

フック追加

コマンド 内容
pre-commit コミット前に実行
pre-push プッシュ前に実行
package.json
"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の有効化

terminal
npx simple-git-hooks

.git/hooks/pre-commit、.git/hooks/pre-pushというファイルが作られます。
git commitを行うと、lint-stagedに指定したコマンドが実行されます。

Polyfillの追加(旧ブラウザ対応)

IE11など旧ブラウザでTypeScriptのトランスパイルによる構文の書き換えで対応できない機能を追加します。

SCSSの旧ブラウザ対応は.browserslistで、TipeScriptの旧ブラウザ対応はtsconfigのtargetで指定していますが、書き方の変更では対応できない部分について、機能追加を行います。

axiosはPromiseが必要ですが、IE11は非対応です。
試しにaxiosを使ってみます。

axiosのインストール

terminal
npm i -S axios

サンプルコード

index.ts
//外部ライブラリインポート確認
import axios from "axios";

//外部ライブラリ動作確認
axios.get("https://jsonplaceholder.typicode.com/users").then((res) => {
  console.log(res);
});

IE11でconsoleを開くと、Promiseが無いため作動していません。

インストール

terminal
npm i -S core-js@3 
npm i -S regenerator

インポート

エンドポイントのindex.tsの一番上にPolyfillインポートを追加

index.ts
//Polyfill
import "core-js";

//Can't resolve 'regenerator-runtime/runtime'が表示されたとき(async awaitを使う場合など)
//import  regeneratorRuntime  from  "regenerator-runtime" ;

動作確認

IE11でconsoleを開くと、エラーが消えてJSONが取得されています。

core-jsをインポートしておくと、必要なPolyfillが自動的に読み込まれるようになります。

テスト

Jestを使えるようにします。

インストール

terminal
npm i -D jest
npm i -D ts-jest
npm i -D @types/jest

npmコマンド追加

package.json
"scripts": {
  "test": "jest"
}

設定ファイル

jest.config.js
module.exports = {
  "roots": [
    "<rootDir>/src/ts/"
  ],
  "testMatch": [
    "**/__tests__/**/*.+(ts|tsx|js)",
    "**/?(*.)+(spec|test).+(ts|tsx|js)"
  ],
  "transform": {
    "^.+\\.(ts|tsx)$": "ts-jest"
  },
}

eslintrc.jsonの変更

Eslintでテストコードにエラーが出ないように、jestを追加

.eslintrc.json
"env": {
  "browser": true,
  "node":true,
  "jest": true
},

コードのサンプル

テスト用サンプルコード

src\ts\test_for_jest.ts
export const calc = (x: number, y: number) => {
  return x + y;
}

テストコード

src\ts__tests__\test_for_jest.spec.ts
import { calc } from "../test_for_jest";
 
describe("関数calcの動作確認", () => {
  it("3+4=7になる", () => {
    expect(calc(1, 8)).toBe(9);
  });
});

動作確認

terminal
npm run test

本番公開対応

/dist/配下のCSS、JavaScriptのminifyを行います。

インストール

terinal
npm i -D uglify-es
npm i -D clean-css-cli

npmコマンド追加

package.json
"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",
  "delete:map":"rimraf dist/**/*.map",
  "prepare:all":"run-p min:js min:css delete:map"
}

動作確認

terminal
npm run prepare:all

/dist/配下のファイルをアップロードします

まとめ

使用時準備

termina;
git clone https://github.com/takeshisakuma/disorder.git
cd disorder
npm ci
npx simple-git-hooks

Web制作時

terminal
npm run watch:all

コード整形時

terminal
npm run format:all

テスト

terminal
npm run test

公開

不要ファイル削除、minify

terminal
npm run prepare:all

dist配下のファイルをそのままアップロードします

リポジトリ

13
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
8