From 403becbf78cc3767becbc5331f48b4554a6a3645 Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Tue, 16 Mar 2021 20:02:08 +0100 Subject: [PATCH] Added support for watch mode --- package-lock.json | 9 +++++ package.json | 1 + plugin/plugin.ts | 94 ++++++++++++++++++++++++++++++----------------- 3 files changed, 71 insertions(+), 33 deletions(-) diff --git a/package-lock.json b/package-lock.json index d7ebce6..740e484 100644 --- a/package-lock.json +++ b/package-lock.json @@ -76,6 +76,15 @@ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.46.tgz", "integrity": "sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg==" }, + "@types/fs-extra": { + "version": "9.0.8", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.8.tgz", + "integrity": "sha512-bnlTVTwq03Na7DpWxFJ1dvnORob+Otb8xHyUqUWhqvz/Ksg8+JXPlR52oeMSZ37YEOa5PyccbgUNutiQdi13TA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/glob": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", diff --git a/package.json b/package.json index 9680201..1ab0809 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "type": "git" }, "devDependencies": { + "@types/fs-extra": "^9.0.8", "@types/react": "^17.0.3", "@types/react-dom": "^17.0.2", "@types/tapable": "^1.0.6", diff --git a/plugin/plugin.ts b/plugin/plugin.ts index 8ce9156..26cb502 100644 --- a/plugin/plugin.ts +++ b/plugin/plugin.ts @@ -1,6 +1,9 @@ import * as path from "path"; -import * as fs from "fs-extra"; +import * as SystemFs from "fs-extra"; import sha1 from "sha1"; +import util from "util"; + +import webpack, {Compiler, Module, RuntimeGlobals} from "webpack"; import { GeneratedSprite, @@ -10,13 +13,10 @@ import { SpriteCssOptions, SpriteDtsOptions } from "./generator"; +import Compilation = webpack.Compilation; -const Module = require("webpack/lib/Module"); -const RuntimeGlobals = require("webpack/lib/RuntimeGlobals"); const { RawSource } = require("webpack-sources"); -import {Compiler} from "webpack"; - export interface Options { modulePrefix?: string, /* defaults to svg-sprites/ */ dtsOutputFolder: string, @@ -74,17 +74,31 @@ class SvgSpriteModule extends Module { } needBuild(context, callback) { - callback(null, !this.buildMeta); + context.fileSystemInfo.getContextHash(this.config.folder, (error, hash) => { + if(error) { + callback(error); + return; + } + + const needBuild = this.buildMeta?.directoryHash !== hash; + callback(null, needBuild); + }) } - build(options, compilation, resolver, fs_, callback) { - console.info("Building SVG sprite for configuration %s", this.configName); + build(options, compilation: Compilation, resolver, fs, callback) { + this.buildAsync(options, compilation).then(() => { + callback(); + }).catch(error => { + callback(error); + }); + } - this.built = true; + private async buildAsync(options_, compilation: Compilation) { this.buildMeta = { async: false, exportsType: undefined }; + this.buildInfo = { cacheable: true, assets: {}, @@ -94,31 +108,36 @@ class SvgSpriteModule extends Module { delete compilation.assets[this.spriteAssetName]; } - (async () => { - const files = (await fs.readdir(this.config.folder)).map(e => path.join(this.config.folder, e)); - this.sprite = await generateSprite(files); - - this.spriteSvg = await generateSpriteSvg(this.sprite); - this.spriteAssetName = "sprite-" + sha1(this.spriteSvg).substr(-20) + ".svg"; - this.spriteAssetUrl = this.spriteAssetName; - - this.buildInfo.assets[this.spriteAssetName] = new RawSource(this.spriteSvg); - - this.spriteCss = ""; - for(const cssOption of this.config.cssOptions) { - this.spriteCss += await generateSpriteCss(cssOption, this.config.cssClassPrefix, this.sprite, this.spriteAssetUrl); - } - - this.spriteJs = await generateSpriteJs(this.config.dtsOptions, this.sprite, this.spriteAssetUrl, this.config.cssClassPrefix); - - const dtsContent = await generateSpriteDts(this.config.dtsOptions, this.configName, this.sprite, this.config.cssClassPrefix, this.pluginConfig.modulePrefix, this.config.folder); - await fs.writeFile(path.join(this.pluginConfig.dtsOutputFolder, this.configName + ".d.ts"), dtsContent); - })().then(() => { - callback(); - }).catch(error => { - console.error(error); - callback("failed to generate sprite"); + this.buildMeta.directoryHash = await new Promise((resolve, reject) => { + compilation.fileSystemInfo.getContextHash(this.config.folder, (err, hash) => { + if(err) { + reject(err); + } else { + resolve(hash); + } + }); }); + compilation.logger.info("Building SVG sprite for configuration %s (Hash: %s).", this.configName, this.buildMeta.directoryHash); + + const files = await SystemFs.readdir(this.config.folder); + this.sprite = await generateSprite(files.map(file => path.join(this.config.folder, file))); + + this.spriteSvg = await generateSpriteSvg(this.sprite); + this.spriteAssetName = "sprite-" + sha1(this.spriteSvg).substr(-20) + ".svg"; + this.spriteAssetUrl = this.spriteAssetName; + + this.buildInfo.assets[this.spriteAssetName] = new RawSource(this.spriteSvg); + + this.spriteCss = ""; + for(const cssOption of this.config.cssOptions) { + this.spriteCss += await generateSpriteCss(cssOption, this.config.cssClassPrefix, this.sprite, this.spriteAssetUrl); + } + + this.spriteJs = await generateSpriteJs(this.config.dtsOptions, this.sprite, this.spriteAssetUrl, this.config.cssClassPrefix); + + const dtsContent = await generateSpriteDts(this.config.dtsOptions, this.configName, this.sprite, this.config.cssClassPrefix, this.pluginConfig.modulePrefix, this.config.folder); + await SystemFs.writeFile(path.join(this.pluginConfig.dtsOutputFolder, this.configName + ".d.ts"), dtsContent); + compilation.logger.info("SVG sprite configuration %s contains %d/%d sprites", this.configName, this.sprite.entries.length, files.length); } codeGeneration(context) { @@ -155,6 +174,15 @@ class SvgSpriteModule extends Module { } addReason(_requestModule, _dependency) { } + + addCacheDependencies( + fileDependencies, + contextDependencies, + missingDependencies, + buildDependencies + ) { + contextDependencies.add(this.config.folder); + } }