@rws-framework/client 2.9.13 → 2.9.15
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/README.md +1 -11
- package/cfg/build_steps/webpack/_loaders.js +0 -2
- package/cfg/build_steps/webpack/_production.js +38 -0
- package/package.json +8 -11
- package/rws.webpack.config.js +11 -32
- package/src/client/config.ts +12 -12
- package/src/components/_attrs/_external_handler.ts +0 -0
- package/src/components/_component.ts +15 -80
- package/src/components/_definitions.ts +63 -0
- package/src/components/_event_handling.ts +34 -0
- package/src/types/IRWSPlugin.ts +0 -0
- package/webpack/loaders/rws_fast_html_loader.js +0 -0
- package/webpack/loaders/rws_fast_scss_loader.js +3 -3
- package/webpack/loaders/rws_fast_ts_loader.js +2 -2
- package/webpack/rws_scss_plugin.js +19 -362
- package/webpack/scss/_compiler.js +99 -0
- package/webpack/scss/_fonts.js +81 -0
- package/webpack/scss/_fs.js +85 -0
- package/webpack/scss/_import.js +187 -0
|
@@ -1,26 +1,22 @@
|
|
|
1
|
-
const sass = require('sass');
|
|
2
|
-
const fs = require('fs');
|
|
3
1
|
const path = require('path');
|
|
4
|
-
const { getTokenSourceMapRange } = require('typescript');
|
|
5
2
|
const _tools = require('../_tools');
|
|
6
|
-
const { rwsPath } = require('@rws-framework/console');
|
|
7
|
-
const _COMPILE_DIR_NAME = 'compiled';
|
|
8
3
|
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
|
|
4
|
+
const _scss_compiler_builder = require('./scss/_compiler');
|
|
5
|
+
let _scss_compiler = null;
|
|
6
|
+
const _scss_import_builder = require('./scss/_import');
|
|
7
|
+
let _scss_import = null;
|
|
8
|
+
const _scss_fs_builder = require('./scss/_fs');
|
|
9
|
+
let _scss_fs = null;
|
|
10
|
+
|
|
13
11
|
|
|
14
|
-
const log = (args) => {
|
|
15
|
-
if (_DEV) {
|
|
16
|
-
console.log(args);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
12
|
class RWSScssPlugin {
|
|
20
13
|
autoCompile = [];
|
|
21
14
|
|
|
22
15
|
constructor(params) {
|
|
23
16
|
this.node_modules_dir = (fileDir) => path.relative(fileDir, _tools.findRootWorkspacePath(process.cwd())) + '/node_modules/'
|
|
17
|
+
_scss_import = _scss_import_builder(this);
|
|
18
|
+
_scss_fs = _scss_fs_builder(this);
|
|
19
|
+
_scss_compiler = _scss_compiler_builder(this);
|
|
24
20
|
|
|
25
21
|
if (!params) {
|
|
26
22
|
params = {};
|
|
@@ -36,366 +32,27 @@ class RWSScssPlugin {
|
|
|
36
32
|
}
|
|
37
33
|
}
|
|
38
34
|
|
|
39
|
-
|
|
40
|
-
let match;
|
|
41
|
-
const imports = [];
|
|
42
|
-
|
|
43
|
-
while ((match = CSS_IMPORT_REGEX.exec(fileContent)) !== null) {
|
|
44
|
-
const importPath = match[1];
|
|
45
|
-
const importLine = match[0];
|
|
46
|
-
|
|
47
|
-
if(fs.statSync(importRootPath).isFile()){
|
|
48
|
-
importRootPath = path.dirname(importRootPath);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const processedImportPath = this.processImportPath(importPath, importRootPath);
|
|
52
|
-
|
|
53
|
-
imports.push([processedImportPath, importLine, path.resolve(processedImportPath)]);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return [imports, fileContent];
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
extractScssUses(fileContent) {
|
|
60
|
-
let match;
|
|
61
|
-
const uses = [];
|
|
62
|
-
|
|
63
|
-
while ((match = SCSS_USE_REGEX.exec(fileContent)) !== null) {
|
|
64
|
-
const usesPath = match[1];
|
|
65
|
-
const usesLine = match[0];
|
|
66
|
-
|
|
67
|
-
if(!uses.find((item) => {
|
|
68
|
-
return item[0] == usesPath
|
|
69
|
-
}) && !usesPath !== 'sass:math'){
|
|
70
|
-
uses.push([usesPath, usesLine]);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// console.log(uses);
|
|
75
|
-
|
|
76
|
-
return [uses];
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
detectImports(code) {
|
|
80
|
-
return CSS_IMPORT_REGEX.test(code);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
writeCssFile(scssFilePath, cssContent) {
|
|
84
|
-
const cssFilePath = scssFilePath.replace('.scss', '.css');
|
|
85
|
-
let endCssFilePath = cssFilePath.split('/');
|
|
86
|
-
let endCssDir = [...endCssFilePath];
|
|
87
|
-
endCssDir[endCssDir.length - 1] = `${_COMPILE_DIR_NAME}`;
|
|
88
|
-
endCssDir = endCssDir.join('/');
|
|
89
|
-
|
|
90
|
-
if (!fs.existsSync(endCssDir)) {
|
|
91
|
-
fs.mkdirSync(endCssDir);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
endCssFilePath[endCssFilePath.length - 1] = `${_COMPILE_DIR_NAME}/` + endCssFilePath[endCssFilePath.length - 1];
|
|
95
|
-
endCssFilePath = endCssFilePath.join('/');
|
|
96
|
-
|
|
97
|
-
fs.writeFileSync(endCssFilePath, cssContent);
|
|
98
|
-
log('Saved CSS file: ' + endCssFilePath);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
hasFontEmbeds(css) {
|
|
102
|
-
return FONT_REGEX.test()
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
embedFontsInCss(css, cssFilePath) {
|
|
106
|
-
let match;
|
|
107
|
-
|
|
108
|
-
while ((match = FONT_REGEX.exec(css)) !== null) {
|
|
109
|
-
const fontPath = match[1];
|
|
110
|
-
const absoluteFontPath = path.resolve(path.dirname(cssFilePath), fontPath);
|
|
111
|
-
|
|
112
|
-
if (fs.existsSync(absoluteFontPath)) {
|
|
113
|
-
const fontData = fs.readFileSync(absoluteFontPath);
|
|
114
|
-
const base64Font = fontData.toString('base64');
|
|
115
|
-
const fontMimeType = this.getFontMimeType(path.extname(absoluteFontPath));
|
|
116
|
-
const fontDataURL = `data:${fontMimeType};base64,${base64Font}`;
|
|
117
|
-
|
|
118
|
-
css = css.replace(new RegExp(match[0], 'g'), `url(${fontDataURL})`);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return css;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
getFontMimeType(extension) {
|
|
126
|
-
switch (extension) {
|
|
127
|
-
case '.woff': return 'font/woff';
|
|
128
|
-
case '.woff2': return 'font/woff2';
|
|
129
|
-
case '.eot': return 'application/vnd.ms-fontobject';
|
|
130
|
-
case '.ttf': return 'font/ttf';
|
|
131
|
-
case '.otf': return 'font/otf';
|
|
132
|
-
default: return 'application/octet-stream';
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
35
|
+
|
|
136
36
|
apply(compiler) {
|
|
137
37
|
const _self = this;
|
|
138
38
|
|
|
139
39
|
return;
|
|
140
40
|
}
|
|
141
41
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
try {
|
|
146
|
-
const files = fs.readdirSync(dirPath);
|
|
147
|
-
|
|
148
|
-
files.forEach(file => {
|
|
149
|
-
const filePath = path.join(dirPath, file);
|
|
150
|
-
const stat = fs.statSync(filePath);
|
|
151
|
-
|
|
152
|
-
if (stat.isFile() && path.extname(file) === '.scss') {
|
|
153
|
-
scssFiles.push(filePath);
|
|
154
|
-
} else if (stat.isDirectory()) {
|
|
155
|
-
scssFiles = scssFiles.concat(readSCSSFilesFromDirectory(filePath));
|
|
156
|
-
}
|
|
157
|
-
});
|
|
158
|
-
} catch (e) {
|
|
159
|
-
console.error(`Failed to read directory ${dirPath}:`, e);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
return scssFiles;
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
getCodeFromFile(filePath) {
|
|
167
|
-
filePath = filePath.replace('//', '/');
|
|
168
|
-
|
|
169
|
-
if (!fs.existsSync(filePath)) {
|
|
170
|
-
const processedImportPath = this.processImportPath(filePath, path.dirname(filePath));
|
|
42
|
+
async compileFile(scssPath) {
|
|
43
|
+
scssPath = _scss_import.processImportPath(scssPath, path.dirname(scssPath))
|
|
171
44
|
|
|
172
|
-
|
|
173
|
-
throw new Error(`SCSS loader: File path "${filePath}" was not found.`);
|
|
174
|
-
}
|
|
45
|
+
let scssCode = _scss_fs.getCodeFromFile(scssPath);
|
|
175
46
|
|
|
176
|
-
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
if (filePath[filePath.length - 1] === '/' && fs.statSync(filePath).isDirectory()) {
|
|
180
|
-
let collectedCode = '';
|
|
181
|
-
|
|
182
|
-
this.readSCSSFilesFromDirectory(filePath).forEach(scssPath => {
|
|
183
|
-
collectedCode += fs.readFileSync(scssPath, 'utf-8');
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
return collectedCode;
|
|
187
|
-
} else if (fs.statSync(filePath).isDirectory()) {
|
|
188
|
-
throw new Error(`Non-directory path (not ending with "/") "${filePath}" is and should not be a directory`)
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
return fs.readFileSync(filePath, 'utf-8');
|
|
47
|
+
return await _scss_compiler.compileScssCode(scssCode, path.dirname(scssPath));
|
|
192
48
|
}
|
|
193
49
|
|
|
194
|
-
|
|
195
|
-
return
|
|
50
|
+
async compileScssCode(scssCode, scssPath){
|
|
51
|
+
return await _scss_compiler.compileScssCode(scssCode, scssPath);
|
|
196
52
|
}
|
|
197
53
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
let scssCode = this.getCodeFromFile(scssPath);
|
|
202
|
-
|
|
203
|
-
return await this.compileScssCode(scssCode, path.dirname(scssPath));
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
processImports(imports, fileRootDir, importStorage = {}, sub = false) {
|
|
207
|
-
const importResults = [];
|
|
208
|
-
|
|
209
|
-
const getStorage = (sourceComponentPath, importedFileContent) => {
|
|
210
|
-
const sourceComponentPathFormatted = sourceComponentPath.replace('/', '_');
|
|
211
|
-
|
|
212
|
-
if (!(sourceComponentPathFormatted in importStorage)) {
|
|
213
|
-
importStorage[sourceComponentPathFormatted] = importedFileContent;
|
|
214
|
-
|
|
215
|
-
return importedFileContent;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
return '';
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
imports.forEach(importData => {
|
|
222
|
-
const originalImportPath = importData[0];
|
|
223
|
-
let importPath = this.processImportPath(originalImportPath, fileRootDir);
|
|
224
|
-
let replacedScssContent = getStorage(importPath, this.getCodeFromFile(importPath).replace(/\/\*[\s\S]*?\*\//g, ''));
|
|
225
|
-
|
|
226
|
-
const recursiveImports = this.extractScssImports(replacedScssContent, importPath)[0];
|
|
227
|
-
|
|
228
|
-
if (recursiveImports.length) {
|
|
229
|
-
|
|
230
|
-
replacedScssContent = this.replaceImports(this.processImports(recursiveImports, path.dirname(importPath), importStorage, true), replacedScssContent);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
importResults.push({
|
|
234
|
-
line: importData[1],
|
|
235
|
-
code: replacedScssContent
|
|
236
|
-
});
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
return importResults;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
replaceImports(processedImports, code) {
|
|
243
|
-
processedImports.forEach(importObj => {
|
|
244
|
-
code = code.replace(importObj.line, importObj.code);
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
return code;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
convertFontToBase64(fontPath) {
|
|
251
|
-
return fs.readFileSync(fontPath, { encoding: 'base64' });
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
replaceFontUrlWithBase64(cssContent) {
|
|
255
|
-
const fontFaceRegex = /@font-face\s*\{[^}]*\}/g;
|
|
256
|
-
let fontFaces = [...cssContent.matchAll(fontFaceRegex)];
|
|
257
|
-
|
|
258
|
-
for(const fontFace of fontFaces){
|
|
259
|
-
const fontFaceContent = fontFace[0];
|
|
260
|
-
const urlRegex = /url\((['"]?)([^)'"]+)(\1)\)/g;
|
|
261
|
-
let match;
|
|
262
|
-
|
|
263
|
-
let modifiedFontFaceContent = fontFaceContent;
|
|
264
|
-
|
|
265
|
-
while ((match = urlRegex.exec(fontFaceContent)) !== null) {
|
|
266
|
-
// Create a promise to convert each font to Base64 and replace in CSS
|
|
267
|
-
const base64 = this.convertFontToBase64(this.processImportPath(match[2], null, true));
|
|
268
|
-
const base64Font = `data:font/woff2;base64,${base64}`;
|
|
269
|
-
|
|
270
|
-
modifiedFontFaceContent = modifiedFontFaceContent.replace(match[2], base64Font);
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
cssContent = cssContent.replace(fontFaceContent, modifiedFontFaceContent)
|
|
274
|
-
};
|
|
275
|
-
|
|
276
|
-
return cssContent;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
processImportPath(importPath, fileRootDir = null, noext = false) {
|
|
280
|
-
if (importPath.split('')[0] === '~') {
|
|
281
|
-
return this.fillSCSSExt(this.replaceWithNodeModules(importPath, null, true), noext);
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
if (importPath.indexOf('@rws-mixins') === 0) {
|
|
285
|
-
return path.resolve(rwsPath.findPackageDir(__dirname), 'src', 'styles', 'includes.scss');
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
if (importPath.indexOf('@cwd') === 0) {
|
|
289
|
-
return this.fillSCSSExt(process.cwd() + '/' + importPath.slice(4), noext);
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
if (importPath.split('')[0] === '/') {
|
|
293
|
-
|
|
294
|
-
return this.fillSCSSExt(importPath, noext);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
if(fileRootDir){
|
|
298
|
-
const relativized = path.resolve(fileRootDir) + '/' + importPath;
|
|
299
|
-
|
|
300
|
-
if (importPath.split('')[0] === '.') {
|
|
301
|
-
return this.fillSCSSExt(relativized, noext);
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
if (!fs.existsSync(relativized)) {
|
|
305
|
-
const partSplit = relativized.split('/');
|
|
306
|
-
partSplit[partSplit.length - 1] = '_' + partSplit[partSplit.length - 1] + '.scss';
|
|
307
|
-
|
|
308
|
-
const newPath = this.underscorePath(relativized);
|
|
309
|
-
|
|
310
|
-
if (fs.existsSync(newPath)) {
|
|
311
|
-
return newPath;
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
return this.fillSCSSExt(relativized, noext);
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
return importPath;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
underscorePath(path, noext = false) {
|
|
321
|
-
const partSplit = path.split('/');
|
|
322
|
-
partSplit[partSplit.length - 1] = '_' + partSplit[partSplit.length - 1] + (path.indexOf('.scss') > - 1 || noext ? '' : '.scss');
|
|
323
|
-
return partSplit.join('/');
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
fillSCSSExt(scssPath, noext = false) {
|
|
327
|
-
const underscoredPath = this.underscorePath(scssPath, noext);
|
|
328
|
-
if (!fs.existsSync(scssPath) && fs.existsSync(underscoredPath)) {
|
|
329
|
-
return underscoredPath;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
if(noext){
|
|
333
|
-
return scssPath;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
if ((!fs.existsSync(scssPath) || (fs.existsSync(scssPath) && fs.statSync(scssPath).isDirectory())) && fs.existsSync(`${scssPath}.scss`)) {
|
|
337
|
-
return `${scssPath}.scss`;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
if (fs.existsSync(`_${scssPath}.scss`)) {
|
|
341
|
-
return `${scssPath}.scss`;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
return scssPath;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
compileScssCode(scssCode, fileRootDir, createFile = false, filePath = null, minify = false) {
|
|
348
|
-
const _self = this;
|
|
349
|
-
const [scssImports] = this.extractScssImports(scssCode, fileRootDir);
|
|
350
|
-
|
|
351
|
-
const dependencies = scssImports.map((item) => item[2]);
|
|
352
|
-
|
|
353
|
-
if (scssImports && scssImports.length) {
|
|
354
|
-
scssCode = this.replaceImports(this.processImports(scssImports, fileRootDir), scssCode);
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
const uses = this.extractScssUses(scssCode)[0];
|
|
358
|
-
let scssUses = '';
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
uses.forEach(scssUse => {
|
|
362
|
-
const useLine = scssUse[1];
|
|
363
|
-
if(scssCode.indexOf(useLine) === -1){
|
|
364
|
-
scssUses += useLine + '\n';
|
|
365
|
-
scssCode = scssCode.replace(useLine + '\n', '');
|
|
366
|
-
}else{
|
|
367
|
-
console.log('ommiting @use. detected in:', fileRootDir, scssUse)
|
|
368
|
-
}
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
scssCode = scssUses + scssCode;
|
|
372
|
-
|
|
373
|
-
try {
|
|
374
|
-
const result = sass.compileString(scssCode, { loadPaths: [fileRootDir]});
|
|
375
|
-
|
|
376
|
-
return { code: this.replaceFontUrlWithBase64(result.css.toString()), dependencies};
|
|
377
|
-
} catch (err) {
|
|
378
|
-
console.error('SASS Error in', fileRootDir);
|
|
379
|
-
|
|
380
|
-
console.error(err);
|
|
381
|
-
throw err;
|
|
382
|
-
return '';
|
|
383
|
-
};
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
checkForImporterType(_module, checkTypeExt) {
|
|
387
|
-
let importingFileExtension = '';
|
|
388
|
-
|
|
389
|
-
if (_module && _module.issuer && _module.issuer.resource) {
|
|
390
|
-
importingFileExtension = path.extname(_module.issuer.resource);
|
|
391
|
-
if (importingFileExtension === ('.' + checkTypeExt)) {
|
|
392
|
-
return true;
|
|
393
|
-
}
|
|
394
|
-
} else {
|
|
395
|
-
return false;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
return false
|
|
54
|
+
writeCssFile(scssFilePath, cssContent){
|
|
55
|
+
return _scss_fs.writeCssFile(scssFilePath, cssContent);
|
|
399
56
|
}
|
|
400
57
|
}
|
|
401
58
|
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
const sass = require('sass');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
const emojiRegex = require('emoji-regex');
|
|
5
|
+
|
|
6
|
+
const _scss_fonts_builder = require('./_fonts');
|
|
7
|
+
let _scss_fonts = null;
|
|
8
|
+
|
|
9
|
+
const _scss_import_builder = require('./_import');
|
|
10
|
+
let _scss_import = null;
|
|
11
|
+
|
|
12
|
+
function compileScssCode(scssCode, fileRootDir, createFile = false, filePath = null, minify = false) {
|
|
13
|
+
_scss_fonts = _scss_fonts_builder(this);
|
|
14
|
+
_scss_import = _scss_import_builder(this);
|
|
15
|
+
|
|
16
|
+
const [scssImports] = _scss_import.extractScssImports(scssCode, fileRootDir);
|
|
17
|
+
|
|
18
|
+
const dependencies = scssImports.map((item) => item[2]);
|
|
19
|
+
|
|
20
|
+
if (scssImports && scssImports.length) {
|
|
21
|
+
scssCode = _scss_import.replaceImports(_scss_import.processImports(scssImports, fileRootDir), scssCode);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const uses = _scss_import.extractScssUses(scssCode)[0];
|
|
25
|
+
let scssUses = '';
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
uses.forEach(scssUse => {
|
|
29
|
+
const useLine = scssUse[1];
|
|
30
|
+
if(scssCode.indexOf(useLine) === -1){
|
|
31
|
+
scssUses += useLine + '\n';
|
|
32
|
+
scssCode = scssCode.replace(useLine + '\n', '');
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
scssCode = removeComments(scssUses + scssCode);
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
const result = sass.compileString(scssCode, { loadPaths: [fileRootDir]});
|
|
40
|
+
|
|
41
|
+
let compiledCode = result.css.toString();
|
|
42
|
+
compiledCode = _scss_fonts.replaceFontUrlWithBase64(compiledCode);
|
|
43
|
+
compiledCode = replaceEmojisWithQuestionMark(compiledCode, fileRootDir);
|
|
44
|
+
|
|
45
|
+
return { code: compiledCode, dependencies};
|
|
46
|
+
} catch (err) {
|
|
47
|
+
console.error('SASS Error in', fileRootDir);
|
|
48
|
+
|
|
49
|
+
console.error(err);
|
|
50
|
+
throw err;
|
|
51
|
+
return '';
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function checkForImporterType(_module, checkTypeExt) {
|
|
56
|
+
let importingFileExtension = '';
|
|
57
|
+
|
|
58
|
+
if (_module && _module.issuer && _module.issuer.resource) {
|
|
59
|
+
importingFileExtension = path.extname(_module.issuer.resource);
|
|
60
|
+
if (importingFileExtension === ('.' + checkTypeExt)) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
} else {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return false
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function replaceEmojisWithQuestionMark(code, componentDir) {
|
|
71
|
+
const regex = emojiRegex();
|
|
72
|
+
let hasEmoji = false;
|
|
73
|
+
|
|
74
|
+
const result = code.replace(regex, (match) => {
|
|
75
|
+
hasEmoji = true;
|
|
76
|
+
return '?';
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
if (hasEmoji) {
|
|
80
|
+
console.log(chalk.yellow(`Emojis in css detected and replaced with "?" in "${path.dirname(componentDir)}" component`));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function removeComments(code) {
|
|
87
|
+
code = code.replace(/\/\/.*$/gm, '');
|
|
88
|
+
code = code.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
89
|
+
code = code.replace(/^\s*$(?:\r\n?|\n)/gm, '');
|
|
90
|
+
|
|
91
|
+
return code;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
module.exports = function(element) {
|
|
95
|
+
return {
|
|
96
|
+
checkForImporterType: checkForImporterType.bind(element),
|
|
97
|
+
compileScssCode: compileScssCode.bind(element)
|
|
98
|
+
};
|
|
99
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const FONT_REGEX = /url\(['"]?(.+?\.(woff|woff2|eot|ttf|otf))['"]?\)/gm;
|
|
4
|
+
|
|
5
|
+
const _scss_import_builder = require('./_import');
|
|
6
|
+
let _scss_import = null;
|
|
7
|
+
|
|
8
|
+
function hasFontEmbeds(css) {
|
|
9
|
+
return FONT_REGEX.test(css);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function embedFontsInCss(css, cssFilePath) {
|
|
13
|
+
let match;
|
|
14
|
+
|
|
15
|
+
while ((match = FONT_REGEX.exec(css)) !== null) {
|
|
16
|
+
const fontPath = match[1];
|
|
17
|
+
const absoluteFontPath = path.resolve(path.dirname(cssFilePath), fontPath);
|
|
18
|
+
|
|
19
|
+
if (fs.existsSync(absoluteFontPath)) {
|
|
20
|
+
const fontData = fs.readFileSync(absoluteFontPath);
|
|
21
|
+
const base64Font = fontData.toString('base64');
|
|
22
|
+
const fontMimeType = getFontMimeType(path.extname(absoluteFontPath));
|
|
23
|
+
const fontDataURL = `data:${fontMimeType};base64,${base64Font}`;
|
|
24
|
+
|
|
25
|
+
css = css.replace(new RegExp(match[0], 'g'), `url(${fontDataURL})`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return css;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function getFontMimeType(extension) {
|
|
33
|
+
switch (extension) {
|
|
34
|
+
case '.woff': return 'font/woff';
|
|
35
|
+
case '.woff2': return 'font/woff2';
|
|
36
|
+
case '.eot': return 'application/vnd.ms-fontobject';
|
|
37
|
+
case '.ttf': return 'font/ttf';
|
|
38
|
+
case '.otf': return 'font/otf';
|
|
39
|
+
default: return 'application/octet-stream';
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function convertFontToBase64(fontPath) {
|
|
44
|
+
return fs.readFileSync(fontPath, { encoding: 'base64' });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function replaceFontUrlWithBase64(cssContent) {
|
|
48
|
+
const fontFaceRegex = /@font-face\s*\{[^}]*\}/g;
|
|
49
|
+
let fontFaces = [...cssContent.matchAll(fontFaceRegex)];
|
|
50
|
+
_scss_import = _scss_import_builder(this);
|
|
51
|
+
|
|
52
|
+
for (const fontFace of fontFaces) {
|
|
53
|
+
const fontFaceContent = fontFace[0];
|
|
54
|
+
const urlRegex = /url\((['"]?)([^)'"]+)(\1)\)/g;
|
|
55
|
+
let match;
|
|
56
|
+
|
|
57
|
+
let modifiedFontFaceContent = fontFaceContent;
|
|
58
|
+
|
|
59
|
+
while ((match = urlRegex.exec(fontFaceContent)) !== null) {
|
|
60
|
+
// Create a promise to convert each font to Base64 and replace in CSS
|
|
61
|
+
const base64 = convertFontToBase64(_scss_import.processImportPath(match[2], null, true));
|
|
62
|
+
const base64Font = `data:font/woff2;base64,${base64}`;
|
|
63
|
+
|
|
64
|
+
modifiedFontFaceContent = modifiedFontFaceContent.replace(match[2], base64Font);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
cssContent = cssContent.replace(fontFaceContent, modifiedFontFaceContent)
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
return cssContent;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
module.exports = function(element) {
|
|
74
|
+
return {
|
|
75
|
+
hasFontEmbeds: hasFontEmbeds.bind(element),
|
|
76
|
+
embedFontsInCss: embedFontsInCss.bind(element),
|
|
77
|
+
getFontMimeType: getFontMimeType.bind(element),
|
|
78
|
+
convertFontToBase64: convertFontToBase64.bind(element),
|
|
79
|
+
replaceFontUrlWithBase64: replaceFontUrlWithBase64.bind(element)
|
|
80
|
+
};
|
|
81
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
let _scss_import = null;
|
|
5
|
+
const _COMPILE_DIR_NAME = 'compiled';
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
function writeCssFile(scssFilePath, cssContent) {
|
|
9
|
+
const cssFilePath = scssFilePath.replace('.scss', '.css');
|
|
10
|
+
let endCssFilePath = cssFilePath.split('/');
|
|
11
|
+
let endCssDir = [...endCssFilePath];
|
|
12
|
+
endCssDir[endCssDir.length - 1] = `${_COMPILE_DIR_NAME}`;
|
|
13
|
+
endCssDir = endCssDir.join('/');
|
|
14
|
+
|
|
15
|
+
if (!fs.existsSync(endCssDir)) {
|
|
16
|
+
fs.mkdirSync(endCssDir);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
endCssFilePath[endCssFilePath.length - 1] = `${_COMPILE_DIR_NAME}/` + endCssFilePath[endCssFilePath.length - 1];
|
|
20
|
+
endCssFilePath = endCssFilePath.join('/');
|
|
21
|
+
|
|
22
|
+
fs.writeFileSync(endCssFilePath, cssContent);
|
|
23
|
+
console.log('Saved external CSS file in: ' + endCssFilePath);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function readSCSSFilesFromDirectory(dirPath) {
|
|
27
|
+
let scssFiles = [];
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const files = fs.readdirSync(dirPath);
|
|
31
|
+
|
|
32
|
+
files.forEach(file => {
|
|
33
|
+
const filePath = path.join(dirPath, file);
|
|
34
|
+
const stat = fs.statSync(filePath);
|
|
35
|
+
|
|
36
|
+
if (stat.isFile() && path.extname(file) === '.scss') {
|
|
37
|
+
scssFiles.push(filePath);
|
|
38
|
+
} else if (stat.isDirectory()) {
|
|
39
|
+
scssFiles = scssFiles.concat(readSCSSFilesFromDirectory(filePath));
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
} catch (e) {
|
|
43
|
+
console.error(`Failed to read directory ${dirPath}:`, e);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return scssFiles;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
function getCodeFromFile(filePath) {
|
|
51
|
+
filePath = filePath.replace('//', '/');
|
|
52
|
+
const _scss_import_builder = require('./_import');
|
|
53
|
+
_scss_import = _scss_import_builder(this);
|
|
54
|
+
|
|
55
|
+
if (!fs.existsSync(filePath)) {
|
|
56
|
+
const processedImportPath = _scss_import.processImportPath(filePath, path.dirname(filePath));
|
|
57
|
+
if (!fs.existsSync(processedImportPath)) {
|
|
58
|
+
throw new Error(`SCSS loader: File path "${filePath}" was not found.`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
filePath = processedImportPath;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (filePath[filePath.length - 1] === '/' && fs.statSync(filePath).isDirectory()) {
|
|
65
|
+
let collectedCode = '';
|
|
66
|
+
|
|
67
|
+
readSCSSFilesFromDirectory(filePath).forEach(scssPath => {
|
|
68
|
+
collectedCode += fs.readFileSync(scssPath, 'utf-8');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
return collectedCode;
|
|
72
|
+
} else if (fs.statSync(filePath).isDirectory()) {
|
|
73
|
+
throw new Error(`Non-directory path (not ending with "/") "${filePath}" is and should not be a directory`)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return fs.readFileSync(filePath, 'utf-8');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
module.exports = function(element) {
|
|
80
|
+
return {
|
|
81
|
+
writeCssFile: writeCssFile.bind(element),
|
|
82
|
+
readSCSSFilesFromDirectory: readSCSSFilesFromDirectory.bind(element),
|
|
83
|
+
getCodeFromFile: getCodeFromFile.bind(element)
|
|
84
|
+
};
|
|
85
|
+
};
|