- 投稿日:
Babelとtscどっちがいいのか気になったので調べて見たメモ
結論から言うと基本的にはtscで良い
確認環境
Env | Ver |
---|---|
@babel/cli | 7.14.5 |
@babel/core | 7.14.6 |
@babel/preset-env | 7.14.7 |
@babel/preset-typescript | 7.14.5 |
typescript | 4.3.2 |
Babelとは何か?
What is Babel? よりBabelとはJavaScriptのコンパイラと説明されている
Babelがしてくれること
- 構文の変換
- corejsを使ったPolyfill
- ソースコードの変換(codemods
- その他色々
基本的にはES6+をES6にしてくれると考えれば良さそうです
でもそれって別にtscでもいいいよねって思う
Babelの導入
基本はこれ
npm i -D @babel/core @babel/cli @babel/preset-env
Babelの設定
.babelrc
を作ってその中にJSONを書いていく
こんな感じ
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"edge": "17",
"ie": "11",
"safari": "11.1"
},
"useBuiltIns": "usage",
"corejs": 3
}
]
]
}
Babelの機能について
コンポーネント
@babel/cli
BabelのCLI、これがないと始まらない
@babel/core
Babel本体、CLIがよしなにしてくれる
@babel/preset-env
構文の変換やPolyfillを設定できる
@babel/preset-typescript
TSをトランスパイルしてくれる
BabelとBrowserlist
BabelはBrowserlistの設定を認識して自動でPolyfillを挿入してくれます
なお、Babel 7.4.0以前では設定方法が異なる可能性があります
サンプルコード
IE11をターゲットにした設定のサンプルです
以下のコマンドを流せばPolyfillされたJSが出ることを確認できます
npx babel src -d dest --extensions ".ts"
.babelrc
{
"presets": [
["@babel/preset-env", { "corejs": 3, "useBuiltIns": "usage" }],
["@babel/preset-typescript"]
]
}
.browserlist
ie 11
Babelとtscでトランスパイルしてみる
割と違うコードが出てきます
元のソース
const sp = new URLSearchParams('?aaa=bbb&ccc');
console.log(sp);
const prm = new Promise((res) => res(true));
console.log(prm);
[...Array(10)].forEach((_, i) => console.log(i));
console.log(globalThis.Date());
export {};
Babel
.babelrc
{
"presets": [["@babel/preset-env"], ["@babel/preset-typescript"]]
}
ビルド結果
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
function _toConsumableArray(arr) {
return (
_arrayWithoutHoles(arr) ||
_iterableToArray(arr) ||
_unsupportedIterableToArray(arr) ||
_nonIterableSpread()
);
}
function _nonIterableSpread() {
throw new TypeError(
"Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."
);
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))
return _arrayLikeToArray(o, minLen);
}
function _iterableToArray(iter) {
if (
(typeof Symbol !== "undefined" && iter[Symbol.iterator] != null) ||
iter["@@iterator"] != null
)
return Array.from(iter);
}
function _arrayWithoutHoles(arr) {
if (Array.isArray(arr)) return _arrayLikeToArray(arr);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++) {
arr2[i] = arr[i];
}
return arr2;
}
var sp = new URLSearchParams("?aaa=bbb&ccc");
console.log(sp);
var prm = new Promise(function (res) {
return res(true);
});
console.log(prm);
_toConsumableArray(Array(10)).forEach(function (_, i) {
return console.log(i);
});
console.log(globalThis.Date());
tsc
tsconfig.json
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"allowJs": true,
"checkJs": true,
"sourceMap": true,
"outDir": "./dist",
"strict": true,
"noImplicitAny": true,
"moduleResolution": "node",
"isolatedModules": true,
"baseUrl": ".",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true
},
"include": ["src/**/*"]
}
ビルド結果
"use strict";
var __spreadArray = (this && this.__spreadArray) || function (to, from) {
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
to[j] = from[i];
return to;
};
Object.defineProperty(exports, "__esModule", { value: true });
var sp = new URLSearchParams('?aaa=bbb&ccc');
console.log(sp);
var prm = new Promise(function (res) { return res(true); });
console.log(prm);
__spreadArray([], Array(10)).forEach(function (_, i) { return console.log(i); });
console.log(globalThis.Date());
//# sourceMappingURL=index.js.map
結論
tscで問題ない
tscの方が綺麗なコードが出てきてるので、Polyfill要らなければtscで問題ないです
因みにES6+をES5にするのもできるのでJSのトランスパイルにも使えます
core-jsを使うならBabel
ちょいちょい触っててBabelの利点はcore-js
があれば.browserlist
を使えるので、そこでターゲットを指定してやればPolyfillを勝手に差し込んでくれるところですね
但しCRAではBabelに対する.browserlistはほぼ無価値
あとはCreate React AppはビルドにBabelを採用しているので、FW側でビルドパイプラインがあるときには採用したほうが楽です
(態々書き換える意味もないので)
ただreact-scripts 4.0.3
にはcore-js
が入っていないので、基本的に.browserlist
を書いたところでPolyfillは入らないため、あんまり存在感はないです
- 投稿日:
Webpackには次の2つの開発モードがあるdevelopment, production
開発モードの設定
mode
プロパティに'development'
, 'production'
, 'none'
を設定する
これを設定するとprocess.env.NODE_ENV
で値を取得できる様になる
それぞれの違いは mode-development にあるが、試してみた感じproductionは出力が最適化され、console系が消えるものと思われる
noneを設定するとminifyとかがされてない生のコードが出てくる
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
+ mode: 'development',
entry: {
index: './src/index.js',
print: './src/print.js',
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
clean: true,
},
plugins: [
new HtmlWebpackPlugin({
title: 'Webpack',
template: 'index.html'
})
]
};
- 投稿日:
基本的なバンドルの続き
複数JSの個別バンドル
src/print.js
を追加して、関係するファイルも幾らか変更する
src/print.js
export const printMe = () => {
console.log('I get called from print.js!');
}
src/index.js
import _ from 'lodash';
-import './index.css';
-import Icon from './icon.png';
+import { printMe } from './print';
function component() {
+ window.onload = printMe;
const div = document.createElement('div');
div.innerHTML = _.join(['Hello', 'webpack'], ' ');
- div.classList.add('hello');
-
- const img = document.createElement('img');
- img.src = Icon;
- div.appendChild(img);
return div;
}
document.body.appendChild(component());
webpack.config.js
const path = require('path');
module.exports = {
- entry: './src/index.js',
+ entry: {
+ index: './src/index.js',
+ print: './src/print.js',
+ },
output: {
- filename: 'bundle.js',
+ filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
},
- module: {
- rules: [
- {
- test: /\.css$/i,
- use: ['style-loader', 'css-loader'],
- },
- {
- test: /\.(png|svg|jpg|jpeg|gif)$/i,
- type: 'asset/resource',
- },
- ],
- },
};
この状態でバンドルするとindex.bundle.jsとprint.bundle.jsが生えてくるが、前回バンドルした残骸が残ってしまう
バンドル時に出力フォルダをクリーンアップする
webpack.config.js
const path = require('path');
module.exports = {
entry: {
index: './src/index.js',
print: './src/print.js',
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
+ clean: true,
},
};
バンドルした内容をHTMLに反映する
この時点のindex.htmlはdist/bundle.jsを参照しているので、今回の結果が反映されていません
これが反映されるように修正します
npm i -D html-webpack-plugin
webpack.config.js
const path = require('path');
+const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
index: './src/index.js',
print: './src/print.js',
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
clean: true,
},
+ plugins: [
+ new HtmlWebpackPlugin({
+ title: 'Webpack',
+ })
+ ]
};
これで設定したバンドルファイルがindex.htmlに反映されるようになりました
HTMLのテンプレートを用意する
しかし先程の設定では出力されるHTMLにどうしても限界があります
HtmlWebpackPlugin のリファレンスを見ることである程度なんとかなりますが、テンプレートに差し込むこともできます
次のように変えることでテンプレートHTMLにバンドルを差し込むことが確認できます
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
index: './src/index.js',
print: './src/print.js',
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
clean: true,
},
plugins: [
new HtmlWebpackPlugin({
title: 'Webpack',
+ template: 'index.html'
})
]
};
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
- <title>Getting Started</title>
</head>
<body>
<script src="dist/bundle.js"></script>
+ <h1>Webpack</h1>
</body>
</html>
- 投稿日:
webpackとはなんぞやというところで軽く調べてみたメモ
ほぼ公式のチュートリアル
やれることが非常に多いので公式ドキュメントを読むのが一番良い
確認環境
Env | ver |
---|---|
webpack | 5.41.0 |
webpack-cli | 4.7.2 |
webpackとは
JavaScriptのモジュールバンドラで次の機能を持つ
- JSやCSS、画像ファイルやデータファイルなどの各種静的ファイルを出力フォルダにまとめて吐く
- ブラウザのキャッシュの影響を回避するために、出力ファイル名を毎回変える
- index.htmlに必要なファイル参照を自動で埋め込む
- 出力フォルダのクリーンアップ
- HMR用のサーバーを起動する
- Sourcemapを吐く
- 次の構成を利用したビルドパイプラインを構成する
- TypeScript, CoffeeScript, Babel and JSX
- その他色々
- 豊富なAPIと設定が存在するのでいろんな事ができる!
webpackを試してみる
取り敢えずこんな感じのプロジェクトを作る
npm init
npm i -D webpack webpack-cli lodash
|- package.json
|- /dist
|- index.html
|- /src
|- index.js
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Getting Started</title>
</head>
<body>
<script src="dist/main.js"></script>
</body>
</html>
src/index.js
import _ from 'lodash';
function component() {
const div = document.createElement('div');
div.innerHTML = _.join(['Hello', 'webpack'], ' ');
return div;
}
document.body.appendChild(component());
npx webpack
を流してバンドルしてあげるとlodashが組み込まれたJSが吐き出される
CSSのバンドル
npm i -D style-loader css-loader
を流してwebpack.config.js
とsrc/index.css
を作成src/index.js
もちょっと書き換えます
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
],
},
};
src/index.css
.hello {
color: red;
}
src/index.js
import _ from 'lodash';
+import './index.css';
function component() {
const div = document.createElement('div');
div.innerHTML = _.join(['Hello', 'webpack'], ' ');
+ div.classList.add('hello');
return div;
}
document.body.appendChild(component());
この状態でnpx webpack
を流すとCSSのバンドルが確認出来る
assetsのバンドル
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
+ {
+ test: /\.(png|svg|jpg|jpeg|gif)$/i,
+ type: 'asset/resource',
+ },
],
},
};
src/index.js
import _ from 'lodash';
import './index.css';
+import Icon from './icon.png';
function component() {
const div = document.createElement('div');
div.innerHTML = _.join(['Hello', 'webpack'], ' ');
div.classList.add('hello');
+ const img = document.createElement('img');
+ img.src = Icon;
+ div.appendChild(img);
return div;
}
document.body.appendChild(component());
フォントファイルやデータファイルのバンドル
基本は同じなので公式のガイドを見るとわかりやすい
- 投稿日:
各サービスの振る舞いが少し気になったので適当にサッと軽く見たメモです
ある程度モダンそうなところを適当に選んだので特に観点とかはないです
確認環境
- Google Chrome 91.0.4472.124(Official Build)
- Cookie offはファーストパーティCookieをブロックして確認
超簡単なまとめ
サービス | Cookie off ログイン | JS off |
---|---|---|
Qiita | エラー | 一部描画が欠損 |
何も起きない | エラー | |
GitHub | エラー | 一部描画が欠損 |
エラー | 一部描画が欠損, 場合によってエラー | |
Youtube | 未確認 | 読込中になる |
mercari | 未確認 | 読込中になる |
DMM | 何も起きない | 一部描画が欠損, 警告が出る, 一部機能不全 |
DLSite | ログアウトページに飛ぶ | 一部描画が欠損, 場合によって例外が出る |
Skeb | 白紙ページ | 白紙ページ |
Tayori | エラー | 一部描画が欠損, 一部機能不全 |
SoundCloud | 何も起きない | エラー |
Qiita
Cookie off
ログインしようとするとエラーになります
JS off
ページの一部が欠損しますが、特にエラーは出ない模様
Cookie off
ログインしようとするとログインページでループします
JS off
エラーが出ます
GitHub
Cookie off
めちゃくちゃシンプルなエラーが出ます
JS off
ページの一部が欠損し、場所によってはエラーになる模様
検索ページとログインページで確認
Cookie off
ログインしようとするとエラーになります
JS off
検索はできましたが、ログインしようとするとエラーになります
Youtube
Cookie off
Googleと同じなのでパス
JS off
読込中の状態で止まります
mercari
Cookie off
未確認
JS off
読込中の状態で止まります
DMM
Cookie off
Twitter同様にログインページでループしました
JS off
ページ上部に通知が生えてきます
ついでにページ表示が崩れたり、一部のページ遷移が機能しなくなりました
DLSite
Cookie off
ログインしようとするとログアウト処理に飛びました
カートにアイテムを入れても入りません
JS off
ページの一部が欠損するので成人向けサイトでも超健全に!
カートからアイテムを消すと謎のエラーが出ますが、カートからは一応消えます
skeb
Cookie off
白紙ページになります
Consoleに次のエラーが出るので想定外ということでしょう
DOMException: Failed to read the 'localStorage' property from 'Window': Access is denied for this document.
JS off
白紙ページになりました
Tayori
Cookie off
エラーになります
JS off
- トップページの一部が欠損
- トップページからヘッダーのリンクを叩くと表示されるコンテンツが白紙に
- ユーザーのFAQページは検索が動作不能
SoundCloud
Cookie off
ログインできずにループします
JS off
エラーになります