モチベーション
nodejs(typescript)でcssを以下のようにstring型で書いていたけど、.css
ファイルで書いた方がVSCodeとかでcssの補完も効くよな。。と思い、実験してみました。
const css = `
.description {
overflow: hidden;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
color: #777;
font-size: 12px;
line-height: 19px;
font-weight: 700;
height: 57px;
}
`
import css from './css';
const style = document.createElement('style');
style.textContent = css;
Webpackでできそう
色々と方法をググっていたら、webpackの公式ドキュメントで以下のような記述を発見。
(実装方法などは後述)
css-loader
toString
You can also use the css-loader results directly as a string, such as in Angular's component style.
css-loader | webpack
元々broserifyでjsなどbundleをしていましたが、ドキュメントの充実度とstackoverflowでの検索ヒット率でwebpackに乗り換えることを決意しました。
browserifyではbroserify-cssというモジュールでcssをトランスフォーム出来るそうです。(今回は試していません)
環境構築
ディレクトリ構成
root/
├ package.json
├ node_modules
├ tsconfig.json
├ webpack.config.js
├ sample.html
├ yarn.lock
├ src/
├ index.ts
├ css.css
├ css.text.css
package.jsonの設定
package.jsonに以下のmoduleを含める。
"devDependencies": {
"@types/node": "^12.11.6",
"css-loader": "^3.4.2",
"to-string-loader": "^1.1.6",
"ts-loader": "^6.2.1",
"typescript": "^3.6.4",
"webpack": "^4.42.0",
"webpack-cli": "^3.3.11"
}
tsconfig.json
各自の設定で大丈夫かと思われます。
{
"compilerOptions": {
"noImplicitAny": false,
"strict": true,
"target": "es5",
"removeComments": true,
"rootDir": "./src/",
"module": "es6",
"sourceMap": false
},
"include": ["src"]
}
webpack.config.jsの設定
今回はmodule.rulesの中で、ファイルの末尾が.css
の場合はモジュールで読み込み、.text.css
のように.text
がファイル名に入っている場合は、string形で読み込めるように設定。
const helpers = require('./webpack-helpers/helpers');
module.exports = {
mode: 'production',
entry: './src/index.ts',
output: {
path: __dirname,
filename: 'bundle.js',
},
resolve: {
extensions: ['.ts', '.js'],
},
module: {
rules: [
{
test: /\.ts$/,
loader: 'ts-loader', //ts-loader使うよ
},
{
test: /\.text\.css$/i,
use: ['to-string-loader', 'css-loader'],
},
{
test: /\.css$/i,
exclude: /text/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true,
}
}],
},
],
},
};
通常通りcssを書く。
#target1{
width: 100px;
height: 100px;
background-color: red;
}
#target2{
width: 100px;
height: 100px;
background-color: red;
opacity: 0.5;
}
cssをtsファイルの中で読み込み
typescirptファイル内で以下のようにcssをインポートすると、string型、またはCSS Modulesで扱えるようになる。
const exec = (): void => {
const cssText: string = require('./main.text.css').toString(); // string
const styles = require('./main.css'); // CSS Modules
const target1 = document.querySelector('#target1');
const target2 = document.querySelector('#target2');
if (target1) {
target1.textContent = 'fuga';
const style = document.createElement('style');
style.textContent = cssText;
document.body.appendChild(style);
}
if (target2) {
const ptag = document.createElement('p');
ptag.textContent = 'fugafuga';
target2.appendChild(ptag);
target2.id = styles.target2;
}
};
exec();
注意点としては、cssをインポートする時はimport
ではなく、require
を使用しなければいけません。
(調査中なので追記をしたいと思います。)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="target1">
hoge
</div>
<div id="target2">
hogehoge
</div>
<script src="bundle.js"></script>
</body>
</html>
これでwebpack
を実行すればファイルがbundleされて、以下のような表示になります。
これでcssファイルで編集できるようになります。
以上。