@konomi-app/k2 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/dev-base.js +1 -1
- package/dist/commands/lint.js +19 -0
- package/dist/commands/plugin-build.js +4 -3
- package/dist/commands/plugin-dev/tailwind.js +1 -3
- package/dist/commands/plugin-dev/upload.js +2 -1
- package/dist/commands/plugin-esbuild.js +61 -0
- package/dist/index.js +3 -1
- package/dist/lib/esbuild-sass-plugin.js +36 -0
- package/dist/lib/esbuild.js +22 -41
- package/dist/lib/lint.js +54 -0
- package/dist/lib/tailwind.js +2 -1
- package/dist/plugin.js +5 -1
- package/package.json +9 -1
- package/types/k2.d.ts +11 -0
- package/types/plugin.d.ts +6 -0
|
@@ -10,7 +10,7 @@ export default function action(params) {
|
|
|
10
10
|
}
|
|
11
11
|
async function build(params) {
|
|
12
12
|
const { entryPoints, staticDir: outdir } = params;
|
|
13
|
-
return buildWithEsbuild({ entryPoints, outdir });
|
|
13
|
+
return buildWithEsbuild({ entryPoints, outdir, watch: true });
|
|
14
14
|
}
|
|
15
15
|
async function server(params) {
|
|
16
16
|
const { certDir, port, staticDir } = params;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { program } from 'commander';
|
|
2
|
+
import { lint } from '../lib/lint.js';
|
|
3
|
+
export default function command() {
|
|
4
|
+
program
|
|
5
|
+
.command('lint')
|
|
6
|
+
.description('Lint source files')
|
|
7
|
+
.option('-c, --config <config>', 'Config file path')
|
|
8
|
+
.action(action);
|
|
9
|
+
}
|
|
10
|
+
export async function action(options) {
|
|
11
|
+
try {
|
|
12
|
+
lint();
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
throw error;
|
|
16
|
+
}
|
|
17
|
+
finally {
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -5,6 +5,7 @@ import { PLUGIN_CONTENTS_DIRECTORY } from '../lib/constants.js';
|
|
|
5
5
|
import { importPluginConfig } from '../lib/import.js';
|
|
6
6
|
import { getTailwindConfig, outputCss } from '../lib/tailwind.js';
|
|
7
7
|
import base from './build-base.js';
|
|
8
|
+
import { lint } from '../lib/lint.js';
|
|
8
9
|
export default function command() {
|
|
9
10
|
program
|
|
10
11
|
.command('build')
|
|
@@ -15,6 +16,9 @@ export async function action() {
|
|
|
15
16
|
console.group('🍳 Build the project for production');
|
|
16
17
|
try {
|
|
17
18
|
const config = await importPluginConfig();
|
|
19
|
+
if (config?.lint?.build) {
|
|
20
|
+
await lint();
|
|
21
|
+
}
|
|
18
22
|
if (!fs.existsSync(PLUGIN_CONTENTS_DIRECTORY)) {
|
|
19
23
|
await fs.mkdir(PLUGIN_CONTENTS_DIRECTORY, { recursive: true });
|
|
20
24
|
}
|
|
@@ -26,16 +30,13 @@ export async function action() {
|
|
|
26
30
|
const tailwindConfig = await getTailwindConfig(config.tailwind);
|
|
27
31
|
const inputFile = path.resolve(config.tailwind.css);
|
|
28
32
|
const inputPath = path.resolve(inputFile);
|
|
29
|
-
const css = await fs.readFile(inputPath, 'utf8');
|
|
30
33
|
await outputCss({
|
|
31
|
-
css,
|
|
32
34
|
inputPath,
|
|
33
35
|
outputPath: path.join(PLUGIN_CONTENTS_DIRECTORY, 'config.css'),
|
|
34
36
|
config: tailwindConfig.config,
|
|
35
37
|
});
|
|
36
38
|
console.log('✨ Built config.css');
|
|
37
39
|
await outputCss({
|
|
38
|
-
css,
|
|
39
40
|
inputPath,
|
|
40
41
|
outputPath: path.join(PLUGIN_CONTENTS_DIRECTORY, 'desktop.css'),
|
|
41
42
|
config: tailwindConfig.config,
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import fs from 'fs-extra';
|
|
2
1
|
import path from 'path';
|
|
3
2
|
import { PLUGIN_DEVELOPMENT_DIRECTORY } from '../../lib/constants.js';
|
|
4
3
|
import chokidar from 'chokidar';
|
|
@@ -8,7 +7,6 @@ async function buildTailwindCSS(params) {
|
|
|
8
7
|
const { inputFile, outputFileName, config } = params;
|
|
9
8
|
const inputPath = path.resolve(inputFile);
|
|
10
9
|
const outputPath = path.join(PLUGIN_DEVELOPMENT_DIRECTORY, outputFileName);
|
|
11
|
-
const css = await fs.readFile(inputPath, 'utf8');
|
|
12
10
|
const watcher = chokidar.watch([...(config.content ?? ['./src/**/*.{ts,tsx}']), inputPath], {
|
|
13
11
|
ignored: /node_modules/,
|
|
14
12
|
persistent: true,
|
|
@@ -23,7 +21,7 @@ async function buildTailwindCSS(params) {
|
|
|
23
21
|
if (type === 'add' && !initialScanComplete) {
|
|
24
22
|
return;
|
|
25
23
|
}
|
|
26
|
-
await outputCss({
|
|
24
|
+
await outputCss({ inputPath, outputPath, config });
|
|
27
25
|
console.log(chalk.hex('#e5e7eb')(`${new Date().toLocaleTimeString()} `) +
|
|
28
26
|
chalk.cyan(`[css] `) +
|
|
29
27
|
outputFileName +
|
|
@@ -42,7 +42,8 @@ export const watchContentsAndUploadZip = async (params) => {
|
|
|
42
42
|
catch (error) {
|
|
43
43
|
console.log(chalk.hex('#e5e7eb')(`${new Date().toLocaleTimeString()} `) +
|
|
44
44
|
chalk.cyan(`[upload] `) +
|
|
45
|
-
chalk.red(`failed`)
|
|
45
|
+
chalk.red(`failed`) +
|
|
46
|
+
chalk.hex('#e5e7eb')(`: ${error?.message ?? 'Unknown error'}`));
|
|
46
47
|
}
|
|
47
48
|
};
|
|
48
49
|
const contentsWatcher = chokider.watch(['src/contents/**/*'], {
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { program } from 'commander';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { PLUGIN_CONTENTS_DIRECTORY } from '../lib/constants.js';
|
|
5
|
+
import { importPluginConfig } from '../lib/import.js';
|
|
6
|
+
import { getTailwindConfig, outputCss } from '../lib/tailwind.js';
|
|
7
|
+
import { buildWithEsbuild } from '../lib/esbuild.js';
|
|
8
|
+
export default function command() {
|
|
9
|
+
program
|
|
10
|
+
.command('esbuild')
|
|
11
|
+
.description("Build the project for production. (It's a wrapper of webpack build command.)")
|
|
12
|
+
.action(action);
|
|
13
|
+
}
|
|
14
|
+
export async function action() {
|
|
15
|
+
console.group('🍳 Build the project for production');
|
|
16
|
+
try {
|
|
17
|
+
const config = await importPluginConfig();
|
|
18
|
+
if (!fs.existsSync(PLUGIN_CONTENTS_DIRECTORY)) {
|
|
19
|
+
await fs.mkdir(PLUGIN_CONTENTS_DIRECTORY, { recursive: true });
|
|
20
|
+
}
|
|
21
|
+
const entries = {
|
|
22
|
+
desktop: path.join('src', 'desktop', 'index.ts'),
|
|
23
|
+
config: path.join('src', 'config', 'index.ts'),
|
|
24
|
+
};
|
|
25
|
+
if (config.tailwind?.css && config.tailwind?.config) {
|
|
26
|
+
const tailwindConfig = await getTailwindConfig(config.tailwind);
|
|
27
|
+
const inputFile = path.resolve(config.tailwind.css);
|
|
28
|
+
const inputPath = path.resolve(inputFile);
|
|
29
|
+
await outputCss({
|
|
30
|
+
inputPath,
|
|
31
|
+
outputPath: path.join(PLUGIN_CONTENTS_DIRECTORY, 'config.css'),
|
|
32
|
+
config: tailwindConfig.config,
|
|
33
|
+
});
|
|
34
|
+
console.log('✨ Built config.css');
|
|
35
|
+
await outputCss({
|
|
36
|
+
inputPath,
|
|
37
|
+
outputPath: path.join(PLUGIN_CONTENTS_DIRECTORY, 'desktop.css'),
|
|
38
|
+
config: tailwindConfig.config,
|
|
39
|
+
});
|
|
40
|
+
console.log('✨ Built desktop.css');
|
|
41
|
+
}
|
|
42
|
+
const entryPoints = ['desktop', 'config'].map((dir) => ({
|
|
43
|
+
in: path.join('src', dir, 'index.ts'),
|
|
44
|
+
out: dir,
|
|
45
|
+
}));
|
|
46
|
+
await buildWithEsbuild({
|
|
47
|
+
entryPoints,
|
|
48
|
+
outdir: PLUGIN_CONTENTS_DIRECTORY,
|
|
49
|
+
minify: true,
|
|
50
|
+
sourcemap: false,
|
|
51
|
+
});
|
|
52
|
+
console.log('✨ Built desktop.js and config.js');
|
|
53
|
+
console.log('✨ Build success.');
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
console.groupEnd();
|
|
60
|
+
}
|
|
61
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -6,11 +6,13 @@ import dev from './commands/dev.js';
|
|
|
6
6
|
import viteDev from './commands/dev-vite.js';
|
|
7
7
|
import genkey from './commands/genkey.js';
|
|
8
8
|
import esbuildBuild from './commands/build-esbuild.js';
|
|
9
|
-
|
|
9
|
+
import lint from './commands/lint.js';
|
|
10
|
+
program.name('k2').version('0.9.0').description('k2 - 🍳 kintone kitchen 🍳');
|
|
10
11
|
build();
|
|
11
12
|
viteBuild();
|
|
12
13
|
esbuildBuild();
|
|
13
14
|
dev();
|
|
14
15
|
viteDev();
|
|
15
16
|
genkey();
|
|
17
|
+
lint();
|
|
16
18
|
program.parse(process.argv);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { compile } from 'sass';
|
|
2
|
+
import { resolve } from 'path';
|
|
3
|
+
export const getSassPlugin = () => {
|
|
4
|
+
const pluginName = 'esbuild-plugin-sass';
|
|
5
|
+
return {
|
|
6
|
+
name: pluginName,
|
|
7
|
+
setup(build) {
|
|
8
|
+
build.onResolve({ filter: /\.s[ac]ss$/ }, (args) => ({
|
|
9
|
+
path: resolve(args.resolveDir, args.path),
|
|
10
|
+
namespace: pluginName,
|
|
11
|
+
}));
|
|
12
|
+
build.onLoad({ filter: /.*/, namespace: pluginName }, async (args) => {
|
|
13
|
+
try {
|
|
14
|
+
const result = compile(args.path);
|
|
15
|
+
return {
|
|
16
|
+
contents: result.css,
|
|
17
|
+
loader: 'css',
|
|
18
|
+
watchFiles: [args.path],
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
return {
|
|
23
|
+
pluginName,
|
|
24
|
+
errors: [
|
|
25
|
+
{
|
|
26
|
+
text: error instanceof Error ? error.message : JSON.stringify(error),
|
|
27
|
+
pluginName,
|
|
28
|
+
location: { file: args.path, namespace: pluginName },
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
};
|
package/dist/lib/esbuild.js
CHANGED
|
@@ -1,58 +1,39 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import esbuild from 'esbuild';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
export const getSassPlugin = () => {
|
|
6
|
-
const pluginName = 'esbuild-plugin-sass';
|
|
3
|
+
import { getSassPlugin } from './esbuild-sass-plugin.js';
|
|
4
|
+
const completeBuildOptions = (params) => {
|
|
7
5
|
return {
|
|
8
|
-
name: pluginName,
|
|
9
|
-
setup(build) {
|
|
10
|
-
build.onResolve({ filter: /\.s[ac]ss$/ }, (args) => ({
|
|
11
|
-
path: resolve(args.resolveDir, args.path),
|
|
12
|
-
namespace: pluginName,
|
|
13
|
-
}));
|
|
14
|
-
build.onLoad({ filter: /.*/, namespace: pluginName }, async (args) => {
|
|
15
|
-
try {
|
|
16
|
-
const result = compile(args.path);
|
|
17
|
-
return {
|
|
18
|
-
contents: result.css,
|
|
19
|
-
loader: 'css',
|
|
20
|
-
watchFiles: [args.path],
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
catch (error) {
|
|
24
|
-
return {
|
|
25
|
-
pluginName,
|
|
26
|
-
errors: [
|
|
27
|
-
{
|
|
28
|
-
text: error instanceof Error ? error.message : JSON.stringify(error),
|
|
29
|
-
pluginName,
|
|
30
|
-
location: { file: args.path, namespace: pluginName },
|
|
31
|
-
},
|
|
32
|
-
],
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
|
-
};
|
|
39
|
-
export const getEsbuildContext = async (params) => {
|
|
40
|
-
return esbuild.context({
|
|
41
6
|
bundle: true,
|
|
42
7
|
platform: 'browser',
|
|
8
|
+
...params,
|
|
9
|
+
plugins: [...(params.plugins ?? []), getSassPlugin()],
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
const completeDevBuildOptions = (params) => {
|
|
13
|
+
return completeBuildOptions({
|
|
14
|
+
...params,
|
|
43
15
|
plugins: [
|
|
16
|
+
...(params.plugins ?? []),
|
|
44
17
|
{
|
|
45
18
|
name: 'on-end',
|
|
46
19
|
setup: ({ onEnd }) => onEnd(() => console.log(chalk.hex('#e5e7eb')(`${new Date().toLocaleTimeString()} `) +
|
|
47
20
|
chalk.cyan(`[js] `) +
|
|
48
21
|
`rebuilt`)),
|
|
49
22
|
},
|
|
50
|
-
getSassPlugin(),
|
|
51
23
|
],
|
|
52
|
-
...params,
|
|
53
24
|
});
|
|
54
25
|
};
|
|
26
|
+
export const getEsbuildContext = async (params) => {
|
|
27
|
+
return esbuild.context(completeDevBuildOptions(params));
|
|
28
|
+
};
|
|
55
29
|
export const buildWithEsbuild = async (params) => {
|
|
56
|
-
const
|
|
57
|
-
|
|
30
|
+
const { watch = false, ...rest } = params;
|
|
31
|
+
if (watch) {
|
|
32
|
+
const context = await getEsbuildContext(rest);
|
|
33
|
+
context.watch();
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
const options = completeBuildOptions(rest);
|
|
37
|
+
await esbuild.build(options);
|
|
38
|
+
}
|
|
58
39
|
};
|
package/dist/lib/lint.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { ESLint } from 'eslint';
|
|
2
|
+
export async function lint() {
|
|
3
|
+
const eslint = new ESLint({
|
|
4
|
+
baseConfig: {
|
|
5
|
+
env: {
|
|
6
|
+
browser: true,
|
|
7
|
+
es2021: true,
|
|
8
|
+
},
|
|
9
|
+
extends: [
|
|
10
|
+
'eslint:recommended',
|
|
11
|
+
'plugin:@typescript-eslint/recommended',
|
|
12
|
+
'plugin:react/recommended',
|
|
13
|
+
'prettier',
|
|
14
|
+
],
|
|
15
|
+
parser: '@typescript-eslint/parser',
|
|
16
|
+
parserOptions: {
|
|
17
|
+
ecmaVersion: 'latest',
|
|
18
|
+
sourceType: 'module',
|
|
19
|
+
project: './tsconfig.json',
|
|
20
|
+
ecmaFeatures: {
|
|
21
|
+
jsx: true,
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
plugins: ['@typescript-eslint', 'react'],
|
|
25
|
+
rules: {
|
|
26
|
+
'react/prop-types': 'off',
|
|
27
|
+
},
|
|
28
|
+
overrides: [
|
|
29
|
+
{
|
|
30
|
+
files: ['*.ts', '*.tsx'],
|
|
31
|
+
rules: {
|
|
32
|
+
'react/prop-types': 'off',
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
settings: {
|
|
37
|
+
react: {
|
|
38
|
+
version: 'detect',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
const results = await eslint.lintFiles(['src/**/*.ts', 'src/**/*.tsx']);
|
|
44
|
+
const formatter = await eslint.loadFormatter('stylish');
|
|
45
|
+
const resultText = formatter.format(results);
|
|
46
|
+
console.group('👕 Lint Results');
|
|
47
|
+
console.log(resultText);
|
|
48
|
+
console.groupEnd();
|
|
49
|
+
const hasErrors = results.some((result) => result.errorCount > 0);
|
|
50
|
+
if (hasErrors) {
|
|
51
|
+
console.error('🚨 Lint errors found');
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
}
|
package/dist/lib/tailwind.js
CHANGED
|
@@ -15,7 +15,8 @@ export const getTailwindConfig = async (config) => {
|
|
|
15
15
|
return { desktop: desktopConfig, config: configConfig };
|
|
16
16
|
};
|
|
17
17
|
export const outputCss = async (params) => {
|
|
18
|
-
const { inputPath, outputPath, config,
|
|
18
|
+
const { inputPath, outputPath, config, minify = false } = params;
|
|
19
|
+
const css = await fs.readFile(inputPath, 'utf8');
|
|
19
20
|
const result = await postcss([tailwindcss(config), ...(minify ? [cssnanoPlugin()] : [])]).process(css, {
|
|
20
21
|
from: inputPath,
|
|
21
22
|
to: outputPath,
|
package/dist/plugin.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { program } from 'commander';
|
|
3
3
|
import build from './commands/plugin-build.js';
|
|
4
|
+
import esbuild from './commands/plugin-esbuild.js';
|
|
4
5
|
import dev from './commands/plugin-dev/index.js';
|
|
5
6
|
import genkey from './commands/plugin-genkey.js';
|
|
6
7
|
import init from './commands/plugin-init.js';
|
|
@@ -8,8 +9,10 @@ import manifest from './commands/manifest/index.js';
|
|
|
8
9
|
import test from './commands/test/index.js';
|
|
9
10
|
import upload from './commands/upload/index.js';
|
|
10
11
|
import zip from './commands/plugin-zip.js';
|
|
11
|
-
|
|
12
|
+
import lint from './commands/lint.js';
|
|
13
|
+
program.name('plugin').version('0.9.0').description('🍳 kintone kitchen 🍳 for kintone plugin');
|
|
12
14
|
build();
|
|
15
|
+
esbuild();
|
|
13
16
|
dev();
|
|
14
17
|
genkey();
|
|
15
18
|
init();
|
|
@@ -17,4 +20,5 @@ manifest();
|
|
|
17
20
|
test();
|
|
18
21
|
upload();
|
|
19
22
|
zip();
|
|
23
|
+
lint();
|
|
20
24
|
program.parse(process.argv);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@konomi-app/k2",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "kintone sdk",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -26,6 +26,8 @@
|
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@kintone/plugin-packer": "^8",
|
|
28
28
|
"@kintone/plugin-uploader": "^9",
|
|
29
|
+
"@typescript-eslint/eslint-plugin": "^7.12.0",
|
|
30
|
+
"@typescript-eslint/parser": "^7.12.0",
|
|
29
31
|
"archiver": "^7",
|
|
30
32
|
"chalk": "^5",
|
|
31
33
|
"chokidar": "^3",
|
|
@@ -34,6 +36,12 @@
|
|
|
34
36
|
"cssnano": "^7.0.2",
|
|
35
37
|
"dotenv": "^16",
|
|
36
38
|
"esbuild": "^0.21",
|
|
39
|
+
"eslint": "^8.57.0",
|
|
40
|
+
"eslint-config-prettier": "^9.1.0",
|
|
41
|
+
"eslint-plugin-import": "^2.29.1",
|
|
42
|
+
"eslint-plugin-n": "^17.8.1",
|
|
43
|
+
"eslint-plugin-promise": "^6.2.0",
|
|
44
|
+
"eslint-plugin-react": "^7.34.2",
|
|
37
45
|
"express": "^4",
|
|
38
46
|
"fs-extra": "^11",
|
|
39
47
|
"html-minifier": "^4",
|
package/types/k2.d.ts
CHANGED
|
@@ -32,5 +32,16 @@ declare namespace K2 {
|
|
|
32
32
|
/** 0から65535までのポート番号 */
|
|
33
33
|
port?: number;
|
|
34
34
|
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* tailwindcssを使用している場合、設定ファイルのパスとCSSファイルのパスを指定することで、JavaScriptファイルのビルド時にCSSファイルを生成します
|
|
38
|
+
*
|
|
39
|
+
* @see {@link https://tailwindcss.com/docs/installation | Tailwind CSS}
|
|
40
|
+
*/
|
|
41
|
+
tailwind?: {
|
|
42
|
+
config?: string;
|
|
43
|
+
/** CSSファイルのパス */
|
|
44
|
+
css?: string;
|
|
45
|
+
};
|
|
35
46
|
};
|
|
36
47
|
}
|
package/types/plugin.d.ts
CHANGED
|
@@ -101,6 +101,12 @@ declare namespace Plugin {
|
|
|
101
101
|
/** 0から65535までのポート番号 */
|
|
102
102
|
port?: number;
|
|
103
103
|
};
|
|
104
|
+
|
|
105
|
+
lint?: {
|
|
106
|
+
build?: boolean;
|
|
107
|
+
dev?: boolean;
|
|
108
|
+
};
|
|
109
|
+
|
|
104
110
|
/**
|
|
105
111
|
* tailwindcssを使用している場合、設定ファイルのパスとCSSファイルのパスを指定することで、JavaScriptファイルのビルド時にCSSファイルを生成します
|
|
106
112
|
*
|