Support WebPack 5

pull/1/head
WolverinDEV 2021-03-16 19:20:57 +01:00
parent 3aede0bc1a
commit 73f07f6bea
13 changed files with 2390 additions and 5786 deletions

2
demo/.gitignore vendored
View File

@ -3,3 +3,5 @@ node_modules
app/*.js
app/*.js.map
dist-plugin/

9
demo/app/test.d.ts vendored
View File

@ -2,14 +2,13 @@
* DO NOT MODIFY THIS FILE!
*
* This file has been auto generated by the svg-sprite generator.
* Sprite source directory: D:\git\web\webpack-svg-sprite\demo\sprites
* Sprite count: 21
* Sprite source directory: D:\__on_g__git\web\webpack-svg-sprite\demo\sprites
* Sprite count: 22
*/
declare module "svg-sprites/test" {
export type TestIconClasses = "client-_player_commander_on" | "client-about" | "client-activate_microphone" | "client-add" | "client-add_foe" | "client-add_folder" | "client-add_friend" | "client-addon-collection" | "client-addon" | "client-apply" | "client-arrow_down" | "client-arrow_left" | "client-arrow_right" | "client-arrow_up" | "client-away" | "client-ban_client" | "client-ban_list" | "client-bookmark_add" | "client-bookmark_add_folder" | "client-bookmark_duplicate" | "client-w2g";
export type TestIconClasses = "client-about" | "client-activate_microphone" | "client-add" | "client-add_foe" | "client-add_folder" | "client-add_friend" | "client-addon-collection" | "client-addon" | "client-apply" | "client-arrow_down" | "client-arrow_left" | "client-arrow_right" | "client-arrow_up" | "client-away" | "client-ban_client" | "client-ban_list" | "client-bookmark_add" | "client-bookmark_add_folder" | "client-bookmark_duplicate" | "client-channel_popin" | "client-player_off" | "client-w2g";
export enum TestIcons {
PlayerCommanderOn = "client-_player_commander_on",
About = "client-about",
ActivateMicrophone = "client-activate_microphone",
Add = "client-add",
@ -29,6 +28,8 @@ declare module "svg-sprites/test" {
BookmarkAdd = "client-bookmark_add",
BookmarkAddFolder = "client-bookmark_add_folder",
BookmarkDuplicate = "client-bookmark_duplicate",
ChannelPopin = "client-channel_popin",
PlayerOff = "client-player_off",
W2g = "client-w2g",
}

4476
demo/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,27 +0,0 @@
{
"name": "svg-sprite-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@types/react": "^16.9.45",
"@types/react-dom": "^16.9.8",
"ts-loader": "^8.0.2",
"typescript": "^3.9.7",
"webpack": "^4.44.1",
"webpack-cli": "^3.3.12"
},
"dependencies": {
"fs": "0.0.1-security",
"fs-extra": "^9.0.1",
"html-webpack-plugin": "^4.3.0",
"react": "^16.13.1",
"react-dom": "^16.13.1"
}
}

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<svg id="client-channel_popin" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<g transform="matrix(.66666 0 0 .66666 0 .00016666)">
<path d="m23.707.293c-.391-.391-1.023-.391-1.414 0l-4.97 4.97-2.043-2.043c-.214-.215-.537-.279-.817-.163s-.463.39-.463.693v5.5c0 .414.336.75.75.75h5.5c.303 0 .577-.183.693-.463s.052-.603-.163-.817l-2.043-2.043 4.97-4.97c.391-.391.391-1.023 0-1.414z" fill="#fff"/>
</g>
<g transform="matrix(.66666 0 0 .66666 0 .00016666)">
<path d="m18 19v2c0 .55-.45 1-1 1h-14c-.55 0-1-.45-1-1v-13.95c-1.14.23-2 1.24-2 2.45v12c0 1.38 1.12 2.5 2.5 2.5h15c1.38 0 2.5-1.12 2.5-2.5v-2.5z" fill="#ccc"/>
</g>
<g transform="matrix(.66666 0 0 .66666 0 .00016666)">
<path d="m22 6.25v.87l.19.19c.79.79 1.03 1.96.6 2.99-.18.43-.45.79-.79 1.06v2.64c0 .55-.45 1-1 1h-14c-.55 0-1-.45-1-1v-9h6v-1.25c0-1.12.67-2.11 1.7-2.54s2.21-.19 3 .6l.62.62 2.44-2.43h-13.26c-1.38 0-2.5 1.12-2.5 2.5v12c0 1.38 1.12 2.5 2.5 2.5h15c1.38 0 2.5-1.12 2.5-2.5v-10.26z" fill="#7289da"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -1,8 +1,8 @@
import * as path from "path";
import {Configuration} from "webpack";
import {CleanWebpackPlugin} from "clean-webpack-plugin";
import * as SpriteGenerator from "../plugin";
import * as HtmlWebpackPlugin from "html-webpack-plugin";
import HtmlWebpackPlugin from "html-webpack-plugin";
import * as SpriteGenerator from "../plugin/";
export = {
entry: path.join(__dirname, "app", "index.tsx"),
@ -47,18 +47,23 @@ export = {
rules: [
{
test: /\.tsx?$/,
loader: [
use: [
"ts-loader"
]
}
]
},
mode: process.env.NODE_ENV === "development" ? "development" : "production",
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
port: 9000,
},
resolve: {
extensions: [".ts", ".tsx", ".css", ".js"]
},
output: {
filename: "[name].[contenthash].js",
path: path.resolve(__dirname, "dist")
}
} as Configuration;

3511
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,13 @@
{
"name": "webpack-svg-sprite-generator",
"version": "1.0.17",
"version": "5.0.0",
"description": "",
"main": "plugin.js",
"types": "ts/index.d.ts",
"scripts": {
"build": "webpack"
"build": "webpack",
"build-demo": "webpack --config demo/webpack.config.js",
"serve-demo": "webpack-dev-server --config demo/webpack.config.js"
},
"keywords": [],
"author": "WolverinDEV",
@ -18,21 +20,28 @@
"type": "git"
},
"devDependencies": {
"@types/react": "^17.0.3",
"@types/react-dom": "^17.0.2",
"@types/tapable": "^1.0.6",
"@types/webpack": "^4.41.21",
"@webpack-cli/serve": "^1.3.0",
"change-case": "^4.1.1",
"clean-webpack-plugin": "^3.0.0",
"copy-webpack-plugin": "^6.0.3",
"html-webpack-plugin": "^5.3.1",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"sha1": "^1.1.1",
"ts-loader": "^8.0.2",
"typescript": "^3.9.7",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.2",
"xml-parser": "^1.2.1"
},
"dependencies": {
"path": "^0.12.7",
"webpack": "^4.44.1",
"fs-extra": "^9.0.1",
"potpack": "^1.0.1"
"path": "^0.12.7",
"potpack": "^1.0.1",
"webpack": "^5.26.1"
}
}

View File

@ -1,11 +1,9 @@
import * as fs from "fs-extra";
import * as path from "path";
import * as XMLParser from "xml-parser";
import { pascalCase } from "change-case";
let potpack = require("potpack");
if(typeof potpack !== "function" && potpack.default)
potpack = potpack.default;
import XMLParser from "xml-parser";
import potpack from "potpack";
function generateAttributes(attributes: XMLParser.Attributes) {
const keys = Object.keys(attributes);
@ -50,7 +48,7 @@ export async function generateSpriteSvg(sprite: GeneratedSprite) {
let result = "";
result += `<?xml version="1.0" encoding="utf-8"?>\n`;
result += `<!-- ${sprite.entries.length} icons packed -->\n`;
result += `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="${sprite.width}" height="${sprite.height}" viewBox="0 0 ${sprite.width} ${sprite.height}">\n`;
result += `<svg xmlns="http://www.w3.org/2000/svg" width="${sprite.width}" height="${sprite.height}" viewBox="0 0 ${sprite.width} ${sprite.height}">\n`;
for(const file of sprite.entries) {
const root = file.data.root;
@ -252,13 +250,13 @@ export async function generateSpriteJs(options: SpriteDtsOptions, sprite: Genera
lines.push(`let ClassList = [${sprite.entries.map(e => `"${cssClassPrefix}${e.name}", `)}];`);
lines.push(``);
lines.push(`Object.defineProperty(exports, "__esModule", { value: true });`);
lines.push(`exports.${options.enumName} = Object.freeze(EnumClassList);`);
lines.push(`exports.spriteUrl = SpriteUrl;`);
lines.push(`exports.classList = Object.freeze(ClassList);`);
lines.push(`exports.spriteEntries = Object.freeze(SpriteEntries);`);
lines.push(`exports.spriteWidth = ${sprite.width};`);
lines.push(`exports.spriteHeight = ${sprite.height};`);
lines.push(`Object.defineProperty(module.exports, "__esModule", { value: true });`);
lines.push(`module.exports.${options.enumName} = Object.freeze(EnumClassList);`);
lines.push(`module.exports.spriteUrl = SpriteUrl;`);
lines.push(`module.exports.classList = Object.freeze(ClassList);`);
lines.push(`module.exports.spriteEntries = Object.freeze(SpriteEntries);`);
lines.push(`module.exports.spriteWidth = ${sprite.width};`);
lines.push(`module.exports.spriteHeight = ${sprite.height};`);
return lines.join("\n");
}
@ -291,7 +289,7 @@ export async function generateSprite(files: string[]) : Promise<GeneratedSprite>
}
const rootAttributes = svg.data.root.attributes;
const [ xOff, yOff, width, height ] = rootAttributes["viewBox"].split(" ").map(parseFloat);
const [ /* xOff */, /* yOff */, width, height ] = rootAttributes["viewBox"].split(" ").map(parseFloat);
if(isNaN(width) || isNaN(height)) {
console.warn("Skipping SVG %s because of invalid bounds (Parsed: %d x %d, Values: %o).", file, width, height, rootAttributes["viewBox"].split(" "));

View File

@ -1,7 +1,6 @@
import * as webpack from "webpack";
import * as path from "path";
import * as fs from "fs-extra";
import * as sha1 from "sha1";
import sha1 from "sha1";
import {
GeneratedSprite,
@ -12,6 +11,12 @@ import {
SpriteDtsOptions
} from "./generator";
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,
@ -20,8 +25,6 @@ export interface Options {
}
}
const Module = require("webpack/lib/Module");
const { RawSource } = require("webpack-sources");
interface SvgSpriteConfiguration {
folder: string;
@ -31,34 +34,47 @@ interface SvgSpriteConfiguration {
cssOptions: SpriteCssOptions[];
}
const TYPES = new Set(["javascript"]);
const RUNTIME_REQUIREMENTS = new Set([
RuntimeGlobals.module
]);
class SvgSpriteModule extends Module {
private readonly pluginConfig: Options;
private readonly configName: string;
private readonly config: SvgSpriteConfiguration;
private sprite: GeneratedSprite;
private spriteSvg: string;
private spriteCss: string;
private spriteJs: string;
private spriteAssetName: string;
private spriteAssetUrl: string;
constructor(context: string, pluginConfig: Options, configName: string, config: SvgSpriteConfiguration) {
super("javascript/dynamic", context);
super("javascript/dynamic", null);
this.pluginConfig = pluginConfig;
this.configName = configName;
this.config = config;
this.buildInfo = {};
this.clearDependenciesAndBlocks();
}
getSourceTypes() {
return TYPES;
}
identifier() {
return "svg-sprite/" + this.configName;
}
readableIdentifier() {
return `SVG sprite ` + this.configName;
}
readableIdentifier(requestShortener) {
return `SVG sprite ` + this.configName;
}
needRebuild() {
return false;
needBuild(context, callback) {
callback(null, !this.buildMeta);
}
build(options, compilation, resolver, fs_, callback) {
@ -71,7 +87,7 @@ class SvgSpriteModule extends Module {
};
this.buildInfo = {
cacheable: true,
assets: {}
assets: {},
};
if(this.spriteAssetName) {
@ -84,7 +100,7 @@ class SvgSpriteModule extends Module {
this.spriteSvg = await generateSpriteSvg(this.sprite);
this.spriteAssetName = "sprite-" + sha1(this.spriteSvg).substr(-20) + ".svg";
this.spriteAssetUrl = (compilation.options.output.publicPath || "") + this.spriteAssetName;
this.spriteAssetUrl = this.spriteAssetName;
this.buildInfo.assets[this.spriteAssetName] = new RawSource(this.spriteSvg);
@ -105,7 +121,9 @@ class SvgSpriteModule extends Module {
});
}
source() {
codeGeneration(context) {
const sources = new Map();
const encodedCss = this.spriteCss
.replace(/%/g, "%25")
.replace(/"/g, "%22")
@ -119,7 +137,9 @@ class SvgSpriteModule extends Module {
lines.push(``);
lines.push(`/* initialize typescript objects */`);
lines.push(...this.spriteJs.split("\n"));
return new RawSource(lines.join("\n"));
sources.set("javascript", new RawSource(lines.join("\n")));
return { sources: sources, runtimeRequirements: RUNTIME_REQUIREMENTS };
}
size() {
@ -133,8 +153,11 @@ class SvgSpriteModule extends Module {
hash.update(this.spriteSvg || "none");
super.updateHash(hash, chunkGraph);
}
addReason(_requestModule, _dependency) { }
}
export class SpriteGenerator {
readonly options: Options;
constructor(options: Options) {
@ -143,20 +166,19 @@ export class SpriteGenerator {
this.options.modulePrefix = this.options.modulePrefix || "svg-sprites/";
}
apply(compiler: webpack.Compiler) {
compiler.hooks.thisCompilation.tap("SpriteGenerator", (compilation, { normalModuleFactory }) => {
normalModuleFactory.hooks.factory.tap("SpriteGenerator", factory => (data, callback) => {
if(data.request.startsWith(this.options.modulePrefix)) {
const configName = data.request.substr(this.options.modulePrefix.length);
if(this.options.configurations[configName] === undefined) {
callback("Missing SVG configuration " + configName);
return;
}
callback(null, new SvgSpriteModule(data.request, this.options, configName, this.options.configurations[configName]));
apply(compiler: Compiler) {
compiler.hooks.normalModuleFactory.tap("SpriteGenerator", normalModuleFactory => {
normalModuleFactory.hooks.resolve.tap("SpriteGenerator", resolveData => {
if(!resolveData.request.startsWith(this.options.modulePrefix)) {
return;
}
factory(data, callback);
const configName = resolveData.request.substr(this.options.modulePrefix.length);
if(!this.options.configurations[configName]) {
return;
}
return new SvgSpriteModule(resolveData.request, this.options, configName, this.options.configurations[configName]);
});
});
}

View File

@ -5,7 +5,8 @@
"sourceMap": false,
"declarationDir": "dist/ts",
"declarationMap": false,
"declaration": true
"declaration": true,
"esModuleInterop": true
},
"include": [
"plugin"

View File

@ -51,7 +51,7 @@ export = {
target: "node",
output: {
path: path.resolve(__dirname, "dist"),
path: process.env.OUTPUT_PATH || path.resolve(__dirname, "dist"),
filename: "plugin.js",
libraryTarget: "umd",