crx-monkey-next 0.0.1

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.
Files changed (94) hide show
  1. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/dist/client/src/client/api.d.ts +3 -0
  2. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/dist/client/src/client/api.js +4 -0
  3. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/dist/client/src/client/api.js.map +1 -0
  4. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/dist/client/src/client/i18n.d.ts +17 -0
  5. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/dist/client/src/client/i18n.js +38 -0
  6. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/dist/client/src/client/i18n.js.map +1 -0
  7. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/dist/client/src/client/main.d.ts +16 -0
  8. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/dist/client/src/client/main.js +8 -0
  9. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/dist/client/src/client/main.js.map +1 -0
  10. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/dist/client/src/client/message.d.ts +30 -0
  11. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/dist/client/src/client/message.js +75 -0
  12. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/dist/client/src/client/message.js.map +1 -0
  13. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/dist/client/src/client/runtime.d.ts +43 -0
  14. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/dist/client/src/client/runtime.js +89 -0
  15. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/dist/client/src/client/runtime.js.map +1 -0
  16. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/dist/client/src/node/plugins/tsBundler.d.ts +28 -0
  17. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/dist/client/src/node/plugins/tsBundler.js +151 -0
  18. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/dist/client/src/node/plugins/tsBundler.js.map +1 -0
  19. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/dist/client/src/node/typeDefs.d.ts +200 -0
  20. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/dist/client/src/node/typeDefs.js +2 -0
  21. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/dist/client/src/node/typeDefs.js.map +1 -0
  22. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/dist/client/tsconfig.client.tsbuildinfo +1 -0
  23. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/src/client/api.d.ts +3 -0
  24. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/src/client/api.js +4 -0
  25. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/src/client/api.js.map +1 -0
  26. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/src/client/i18n.d.ts +17 -0
  27. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/src/client/i18n.js +38 -0
  28. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/src/client/i18n.js.map +1 -0
  29. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/src/client/main.d.ts +17 -0
  30. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/src/client/main.js +9 -0
  31. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/src/client/main.js.map +1 -0
  32. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/src/client/message.d.ts +30 -0
  33. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/src/client/message.js +75 -0
  34. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/src/client/message.js.map +1 -0
  35. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/src/client/runtime.d.ts +32 -0
  36. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/src/client/runtime.js +58 -0
  37. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/src/client/runtime.js.map +1 -0
  38. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/src/node/typeDefs.d.ts +189 -0
  39. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/src/node/typeDefs.js +2 -0
  40. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/src/node/typeDefs.js.map +1 -0
  41. package/.rollup.cache/home/yakisova41/crx-monkey-next/packages/crx-monkey/tsconfig.client.tsbuildinfo +1 -0
  42. package/README.md +34 -0
  43. package/bin/crx-monkey +2 -0
  44. package/bun.lockb +0 -0
  45. package/dist/client/main.d.ts +187 -0
  46. package/dist/client/main.js +200 -0
  47. package/dist/client/tsconfig.client.tsbuildinfo +1 -0
  48. package/dist/node/exports.d.ts +213 -0
  49. package/dist/node/exports.js +650 -0
  50. package/dist/node/main.js +2759 -0
  51. package/jest.config.js +17 -0
  52. package/package.json +81 -0
  53. package/rollup.config.js +101 -0
  54. package/src/client/i18n.ts +42 -0
  55. package/src/client/main.ts +20 -0
  56. package/src/client/message.ts +118 -0
  57. package/src/client/runtime.ts +109 -0
  58. package/src/node/BundlerRegisterer.ts +311 -0
  59. package/src/node/ConfigLoader.ts +127 -0
  60. package/src/node/CrxmBundler.ts +213 -0
  61. package/src/node/Distributior.ts +295 -0
  62. package/src/node/Logger.ts +77 -0
  63. package/src/node/Watcher.ts +166 -0
  64. package/src/node/__tests__/config.test.ts +157 -0
  65. package/src/node/__tests__/manifest.test.ts +380 -0
  66. package/src/node/build.ts +64 -0
  67. package/src/node/dev.ts +146 -0
  68. package/src/node/development/CreateDevClient.ts +168 -0
  69. package/src/node/development/codes/extension.ts +187 -0
  70. package/src/node/development/codes/sw.ts +41 -0
  71. package/src/node/development/codes/userjs.ts +150 -0
  72. package/src/node/exports.ts +135 -0
  73. package/src/node/file.ts +45 -0
  74. package/src/node/inversify.config.ts +53 -0
  75. package/src/node/main.ts +34 -0
  76. package/src/node/manifest/ManifestFactory.ts +165 -0
  77. package/src/node/manifest/ManifestLoader.ts +71 -0
  78. package/src/node/manifest/ManifestParser.ts +191 -0
  79. package/src/node/manifest/i18n.ts +93 -0
  80. package/src/node/plugins/htmlBundler/HTMLTools.ts +332 -0
  81. package/src/node/plugins/htmlBundler/main.ts +140 -0
  82. package/src/node/plugins/sassBundler.ts +59 -0
  83. package/src/node/plugins/tsBundler.ts +197 -0
  84. package/src/node/server/FileServer.ts +97 -0
  85. package/src/node/server/SockServer.ts +143 -0
  86. package/src/node/typeDefs.ts +221 -0
  87. package/src/node/types.ts +24 -0
  88. package/src/node/userscript/CodeInjector.ts +164 -0
  89. package/src/node/userscript/UserscriptBundler.ts +138 -0
  90. package/src/node/userscript/UserscriptHeader.ts +76 -0
  91. package/src/node/userscript/UserscriptRegisterer.ts +204 -0
  92. package/src/node/utils.ts +25 -0
  93. package/tsconfig.client.json +20 -0
  94. package/tsconfig.json +24 -0
@@ -0,0 +1,332 @@
1
+ import { parse, HTMLElement } from 'node-html-parser';
2
+ import fse from 'fs-extra';
3
+ import { basename, dirname, resolve } from 'path';
4
+ import { watch, FSWatcher } from 'fs';
5
+ import { CrxmBundlerPlugin, CrxmBundlerPluginWatch, I_CrxmBundler } from '../../typeDefs';
6
+
7
+ export class HTMLTools {
8
+ private htmlParserRoot: HTMLElement;
9
+
10
+ private stackInterval: NodeJS.Timeout | null = null;
11
+ private watcher: FSWatcher | null = null;
12
+ private parseResult: PopupBuilderParsed = {
13
+ requestLocalScripts: {},
14
+ requestLocalHrefFiles: {},
15
+ requestLocalSrcFiles: {},
16
+ };
17
+
18
+ constructor(
19
+ private readonly popupPath: string,
20
+ private readonly distPath: string,
21
+ private readonly plugins: {
22
+ build: Record<string, CrxmBundlerPlugin>;
23
+ watch: Record<string, CrxmBundlerPluginWatch>;
24
+ },
25
+ private readonly bundler: I_CrxmBundler,
26
+ ) {
27
+ this.htmlParserRoot = this.getParser(popupPath);
28
+ }
29
+
30
+ public async build() {
31
+ this.htmlParserRoot = this.getParser(this.popupPath);
32
+ const result = this.parse();
33
+ const diff = this.getParseResultDiff(result);
34
+ this.parseResult = result;
35
+ const hashs = this.registerDiffToBundler(diff);
36
+ this.syncAssets(diff);
37
+ return hashs;
38
+ }
39
+
40
+ public async watchHTML() {
41
+ const stack: (() => Promise<void>)[] = [];
42
+
43
+ const onUpdate = async () => {
44
+ this.htmlParserRoot = this.getParser(this.popupPath);
45
+ const result = this.parse();
46
+
47
+ const diff = this.getParseResultDiff(result);
48
+ this.parseResult = result;
49
+
50
+ this.registerDiffToBundler(diff);
51
+ this.syncAssets(diff);
52
+
53
+ await this.bundler.stopWatch();
54
+ await this.bundler.watch();
55
+ };
56
+
57
+ await onUpdate();
58
+
59
+ this.watcher = watch(this.popupPath);
60
+
61
+ this.watcher.addListener('change', () => {
62
+ stack.push(onUpdate);
63
+ });
64
+
65
+ this.stackInterval = setInterval(async () => {
66
+ if (stack[0] !== undefined) {
67
+ await stack[0]();
68
+ stack.splice(0, 1);
69
+ }
70
+ }, 1000);
71
+ }
72
+
73
+ public stopWatch() {
74
+ if (this.stackInterval !== null) {
75
+ clearInterval(this.stackInterval);
76
+ }
77
+
78
+ if (this.watcher !== null) {
79
+ this.watcher.close();
80
+ }
81
+ }
82
+
83
+ public resolveScript(entry: string, target: string) {
84
+ const targetElement = this.parseResult.requestLocalScripts[this.resolveFilePath(entry)];
85
+ targetElement.setAttribute('src', target);
86
+ }
87
+
88
+ public resolveHref(entry: string, target: string) {
89
+ const targetElement = this.parseResult.requestLocalHrefFiles[this.resolveFilePath(entry)];
90
+ targetElement.setAttribute('href', target);
91
+ }
92
+
93
+ public resolveSrc(entry: string, target: string) {
94
+ const targetElement = this.parseResult.requestLocalSrcFiles[this.resolveFilePath(entry)];
95
+ targetElement.setAttribute('src', target);
96
+ }
97
+
98
+ public outputHtmlResolved() {
99
+ return this.htmlParserRoot.toString();
100
+ }
101
+
102
+ private syncAssets(
103
+ diff: Record<
104
+ 'localScripts' | 'localHrefFiles' | 'localSrcFiles',
105
+ {
106
+ add: string[];
107
+ delete: string[];
108
+ }
109
+ >,
110
+ ) {
111
+ diff.localSrcFiles.add.forEach((filePath: string) => {
112
+ const baseFileName = basename(filePath);
113
+ const newFilePath = '/assets/' + baseFileName;
114
+
115
+ fse.copySync(filePath, resolve(this.distPath, 'assets', baseFileName));
116
+ this.resolveSrc(filePath, newFilePath);
117
+ });
118
+
119
+ diff.localSrcFiles.delete.forEach((filePath: string) => {
120
+ const baseFileName = basename(filePath);
121
+ const newFilePath = '/assets/' + baseFileName;
122
+
123
+ fse.removeSync(newFilePath);
124
+ });
125
+ }
126
+
127
+ private registerDiffToBundler(
128
+ diff: Record<
129
+ 'localScripts' | 'localHrefFiles' | 'localSrcFiles',
130
+ {
131
+ add: string[];
132
+ delete: string[];
133
+ }
134
+ >,
135
+ ) {
136
+ const hashs: string[] = [];
137
+
138
+ const targetGroups: [string, string[]][] = [
139
+ ['html_script', diff.localScripts.add],
140
+ ['html_href', diff.localHrefFiles.add],
141
+ ];
142
+
143
+ for (const [type, paths] of targetGroups) {
144
+ for (const path of paths) {
145
+ if (type === 'html_script' || type === 'html_href') {
146
+ const buildPlugin = this.getAppropriateBuildPlugin(path);
147
+ const watchPlugin = this.getAppropriateWatchPlugin(path);
148
+
149
+ if (!buildPlugin) {
150
+ console.error(`Could not find the appropriate plugin for building "${path}"`);
151
+ continue;
152
+ }
153
+
154
+ if (!watchPlugin) {
155
+ console.error(`Could not find the appropriate plugin for watching "${path}"`);
156
+ continue;
157
+ }
158
+
159
+ const hash = this.bundler.addTarget(
160
+ path,
161
+ { build: buildPlugin, watch: watchPlugin },
162
+ type,
163
+ );
164
+ hashs.push(hash);
165
+ }
166
+ }
167
+ }
168
+
169
+ [...diff.localScripts.delete, ...diff.localHrefFiles.delete].forEach((path) => {
170
+ this.bundler.removeTarget(path);
171
+ });
172
+
173
+ return hashs;
174
+ }
175
+
176
+ /**
177
+ * Get diff that loaded resources in html what with added or deleted.
178
+ * @returns
179
+ */
180
+ private getParseResultDiff(newResult: PopupBuilderParsed) {
181
+ const result: Record<
182
+ 'localScripts' | 'localHrefFiles' | 'localSrcFiles',
183
+ { add: string[]; delete: string[] }
184
+ > = {
185
+ localScripts: {
186
+ add: [],
187
+ delete: [],
188
+ },
189
+ localHrefFiles: {
190
+ add: [],
191
+ delete: [],
192
+ },
193
+ localSrcFiles: {
194
+ add: [],
195
+ delete: [],
196
+ },
197
+ };
198
+
199
+ const setDiff = (
200
+ key: keyof typeof result,
201
+ elements: Record<string, HTMLElement>,
202
+ original: Record<string, HTMLElement>,
203
+ ) => {
204
+ Object.keys(elements).forEach((requestURL) => {
205
+ if (original[requestURL] === undefined) {
206
+ result[key].add.push(requestURL);
207
+ }
208
+ });
209
+
210
+ Object.keys(original).forEach((requestURL) => {
211
+ if (elements[requestURL] === undefined) {
212
+ result[key].delete.push(requestURL);
213
+ }
214
+ });
215
+ };
216
+
217
+ setDiff('localScripts', newResult.requestLocalScripts, this.parseResult.requestLocalScripts);
218
+ setDiff(
219
+ 'localHrefFiles',
220
+ newResult.requestLocalHrefFiles,
221
+ this.parseResult.requestLocalHrefFiles,
222
+ );
223
+ setDiff('localSrcFiles', newResult.requestLocalSrcFiles, this.parseResult.requestLocalSrcFiles);
224
+
225
+ return result;
226
+ }
227
+
228
+ /**
229
+ * Parse popup html
230
+ * @param filePath
231
+ * @returns
232
+ */
233
+ public parse(): PopupBuilderParsed {
234
+ return {
235
+ requestLocalScripts: this.getResourceElement(this.htmlParserRoot, 'script', 'src'),
236
+ requestLocalHrefFiles: this.getResourceElement(this.htmlParserRoot, 'link', 'href'),
237
+ requestLocalSrcFiles: this.getResourceElement(
238
+ this.htmlParserRoot,
239
+ 'video, img, iframe',
240
+ 'src',
241
+ ),
242
+ };
243
+ }
244
+
245
+ /**
246
+ * Get elements for loading any resource. for example, script or img link anymore..
247
+ * @param root
248
+ * @param selector
249
+ * @param resourceURLAttr
250
+ * @returns
251
+ */
252
+ private getResourceElement(root: HTMLElement, selector: string, resourceURLAttr: string) {
253
+ const elems = root.querySelectorAll(selector);
254
+
255
+ const ResultElems: Record<string, HTMLElement> = {};
256
+
257
+ elems.forEach((elem) => {
258
+ const noBundleAttr = elem.getAttribute('no-bundle');
259
+
260
+ if (noBundleAttr !== '' && noBundleAttr !== 'true') {
261
+ const src = elem.getAttribute(resourceURLAttr);
262
+ if (src !== undefined && src !== null) {
263
+ // Except the script href that start http.
264
+ if (src.match('^http.*') === null) {
265
+ const resolvedPath = this.resolveFilePath(src);
266
+
267
+ ResultElems[resolvedPath] = elem;
268
+ }
269
+ }
270
+ }
271
+ });
272
+
273
+ return ResultElems;
274
+ }
275
+
276
+ /**
277
+ * Resolve path
278
+ */
279
+ private resolveFilePath(contentPath: string) {
280
+ return resolve(dirname(this.popupPath), contentPath);
281
+ }
282
+
283
+ /**
284
+ * Get Html parser instance.
285
+ * @param htmlPath
286
+ * @returns
287
+ */
288
+ private getParser(htmlPath: string) {
289
+ const content = fse.readFileSync(htmlPath).toString();
290
+ const root = parse(content);
291
+
292
+ return root;
293
+ }
294
+
295
+ /**
296
+ * Get build plugin
297
+ * @param filePath
298
+ * @returns
299
+ */
300
+ private getAppropriateBuildPlugin(filePath: string) {
301
+ for (const [pattern, plugin] of Object.entries(this.plugins.build)) {
302
+ const regex = new RegExp(pattern);
303
+ if (regex.test(filePath)) {
304
+ return plugin;
305
+ }
306
+ }
307
+
308
+ return null;
309
+ }
310
+
311
+ /**
312
+ * Get watch plugin
313
+ * @param filePath
314
+ * @returns
315
+ */
316
+ private getAppropriateWatchPlugin(filePath: string) {
317
+ for (const [pattern, plugin] of Object.entries(this.plugins.watch)) {
318
+ const regex = new RegExp(pattern);
319
+ if (regex.test(filePath)) {
320
+ return plugin;
321
+ }
322
+ }
323
+
324
+ return null;
325
+ }
326
+ }
327
+
328
+ export interface PopupBuilderParsed {
329
+ requestLocalScripts: Record<string, HTMLElement>;
330
+ requestLocalHrefFiles: Record<string, HTMLElement>;
331
+ requestLocalSrcFiles: Record<string, HTMLElement>;
332
+ }
@@ -0,0 +1,140 @@
1
+ import { CrxmBundlerPlugin, CrxmBundlerPluginWatch } from '../../typeDefs';
2
+ import { basename, resolve } from 'path';
3
+ import { HTMLTools } from './HTMLTools';
4
+ import MurmurHash3 from 'murmurhash3js';
5
+ import fse from 'fs-extra';
6
+
7
+ export interface HtmlBundlerOptions {
8
+ output: string;
9
+ plugins: {
10
+ build: Record<string, CrxmBundlerPlugin>;
11
+ watch: Record<string, CrxmBundlerPluginWatch>;
12
+ };
13
+ }
14
+
15
+ let htmlTools: HTMLTools | null = null;
16
+ let listenerAdded = false;
17
+
18
+ export function htmlBundlerWatch(options: HtmlBundlerOptions): CrxmBundlerPluginWatch {
19
+ return {
20
+ name: 'Crxm Watch HTML Plugin',
21
+ plugin: async (filePath, sendResult, bundler) => {
22
+ const distPath = resolve(options.output);
23
+
24
+ if (htmlTools === null) {
25
+ htmlTools = new HTMLTools(filePath, options.output, options.plugins, bundler);
26
+ await htmlTools.watchHTML();
27
+ }
28
+
29
+ if (!listenerAdded) {
30
+ bundler.addListener((target) => {
31
+ if (htmlTools !== null) {
32
+ if (target.flag === 'html_script' || target.flag === 'html_href') {
33
+ const result = bundler.compileResults[target.hash];
34
+
35
+ if (target.flag === 'html_script') {
36
+ const extChanged = changeExt(target.entryPoint, 'js');
37
+ const endemicHash = MurmurHash3.x86.hash32(target.entryPoint).toString();
38
+
39
+ const fileName = endemicHash + '_' + extChanged;
40
+
41
+ const outputPath = resolve(distPath, fileName);
42
+
43
+ fse.outputFileSync(outputPath, result);
44
+
45
+ htmlTools.resolveScript(target.entryPoint, fileName);
46
+ }
47
+
48
+ if (target.flag === 'html_href') {
49
+ const extChanged = changeExt(target.entryPoint, 'css');
50
+ const endemicHash = MurmurHash3.x86.hash32(target.entryPoint).toString();
51
+
52
+ const fileName = endemicHash + '_' + extChanged;
53
+
54
+ const outputPath = resolve(distPath, fileName);
55
+
56
+ fse.outputFileSync(outputPath, result);
57
+
58
+ htmlTools.resolveHref(target.entryPoint, fileName);
59
+ }
60
+
61
+ const html = htmlTools.outputHtmlResolved();
62
+ const encoder = new TextEncoder();
63
+ const encoded = encoder.encode(html);
64
+
65
+ sendResult(encoded);
66
+ }
67
+ }
68
+ });
69
+ listenerAdded = true;
70
+ }
71
+
72
+ return {
73
+ stop: async () => {
74
+ if (htmlTools !== null) {
75
+ htmlTools.stopWatch();
76
+ htmlTools = null;
77
+ }
78
+ },
79
+ };
80
+ },
81
+ };
82
+ }
83
+
84
+ export function htmlBundler(options: HtmlBundlerOptions): CrxmBundlerPlugin {
85
+ return {
86
+ name: 'Crxm HTML Plugin',
87
+ plugin: async (filePath, bundler) => {
88
+ const distPath = resolve(options.output);
89
+
90
+ const htmlTools = new HTMLTools(filePath, options.output, options.plugins, bundler);
91
+
92
+ const hashs = await htmlTools.build();
93
+
94
+ await Promise.all(
95
+ hashs.map(async (hash) => {
96
+ const target = await bundler.compileForce(hash);
97
+ const result = bundler.compileResults[target.hash];
98
+
99
+ if (target.flag === 'html_script') {
100
+ const extChanged = changeExt(target.entryPoint, 'js');
101
+ const endemicHash = MurmurHash3.x86.hash32(target.entryPoint).toString();
102
+
103
+ const fileName = endemicHash + '_' + extChanged;
104
+
105
+ const outputPath = resolve(distPath, fileName);
106
+
107
+ fse.outputFileSync(outputPath, result);
108
+
109
+ htmlTools.resolveScript(target.entryPoint, fileName);
110
+ }
111
+
112
+ if (target.flag === 'html_href') {
113
+ const extChanged = changeExt(target.entryPoint, 'css');
114
+ const endemicHash = MurmurHash3.x86.hash32(target.entryPoint).toString();
115
+
116
+ const fileName = endemicHash + '_' + extChanged;
117
+
118
+ const outputPath = resolve(distPath, fileName);
119
+ fse.outputFileSync(outputPath, result);
120
+
121
+ htmlTools.resolveHref(target.entryPoint, fileName);
122
+ }
123
+ }),
124
+ );
125
+
126
+ const html = htmlTools.outputHtmlResolved();
127
+ const encoder = new TextEncoder();
128
+ const encoded = encoder.encode(html);
129
+
130
+ return encoded;
131
+ },
132
+ };
133
+ }
134
+
135
+ function changeExt(filePath: string, newExt: string) {
136
+ const rawFileNameSplited = basename(filePath).split('.');
137
+ rawFileNameSplited[rawFileNameSplited.length - 1] = newExt;
138
+ const newFilename = rawFileNameSplited.join('.');
139
+ return newFilename;
140
+ }
@@ -0,0 +1,59 @@
1
+ import { watch } from 'fs';
2
+ import { CrxmBundlerPlugin, CrxmBundlerPluginWatch, CrxmResultSender } from '../typeDefs';
3
+ import { compile, Options } from 'sass';
4
+
5
+ export interface SassBundlerOptions {
6
+ sass: Options<'sync'>;
7
+ }
8
+
9
+ /**
10
+ * Bundle sass
11
+ * @param options
12
+ * @returns
13
+ */
14
+ export function sassBundler(options: SassBundlerOptions = { sass: {} }): CrxmBundlerPlugin {
15
+ return {
16
+ name: 'Crxm Sass Plugin',
17
+ plugin: async (filePath: string) => {
18
+ const result = compile(filePath, options.sass);
19
+ const encoder = new TextEncoder();
20
+ const encoded = encoder.encode(result.css);
21
+ return encoded;
22
+ },
23
+ };
24
+ }
25
+
26
+ /**
27
+ * Watch sass
28
+ * @param options
29
+ * @returns
30
+ */
31
+ export function sassBundlerWatch(
32
+ options: SassBundlerOptions = { sass: {} },
33
+ ): CrxmBundlerPluginWatch {
34
+ return {
35
+ name: 'Crxm Watch Sass Plugin',
36
+ plugin: async (filePath: string, sendResult: CrxmResultSender) => {
37
+ const watcher = watch(filePath);
38
+
39
+ const compileAndSend = () => {
40
+ const result = compile(filePath, options.sass);
41
+ const encoder = new TextEncoder();
42
+ const encoded = encoder.encode(result.css);
43
+ sendResult(encoded);
44
+ };
45
+
46
+ compileAndSend();
47
+
48
+ watcher.addListener('change', () => {
49
+ compileAndSend();
50
+ });
51
+
52
+ return {
53
+ stop: async () => {
54
+ watcher.close();
55
+ },
56
+ };
57
+ },
58
+ };
59
+ }