glass-easel-miniprogram-webpack-plugin 0.2.1 → 0.3.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.
package/index.js CHANGED
@@ -1,409 +1,526 @@
1
- const fs = require('fs').promises
2
- const path = require('path')
3
- const webpack = require('webpack')
4
- const { RawSource } = require('webpack-sources')
5
- const VirtualModulesPlugin = require('webpack-virtual-modules')
6
- const chokidar = require('chokidar')
7
- const { TmplGroup } = require('glass-easel-template-compiler')
8
-
9
- const { escapeJsString } = require('./helpers')
10
-
11
- const GlassEaselMiniprogramWxmlLoader = path.join(__dirname, 'wxml_loader.js')
12
- const GlassEaselMiniprogramWxssLoader = path.join(__dirname, 'wxss_loader.js')
13
-
14
- const PLUGIN_NAME = 'GlassEaselMiniprogramWebpackPlugin'
15
-
1
+ "use strict";
2
+ /* eslint-disable @typescript-eslint/no-var-requires */
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || function (mod) {
20
+ if (mod && mod.__esModule) return mod;
21
+ var result = {};
22
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
23
+ __setModuleDefault(result, mod);
24
+ return result;
25
+ };
26
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
27
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
28
+ return new (P || (P = Promise))(function (resolve, reject) {
29
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
30
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
31
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
32
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
33
+ });
34
+ };
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.GlassEaselMiniprogramWebpackPlugin = exports.GlassEaselMiniprogramWxssLoader = exports.GlassEaselMiniprogramWxmlLoader = void 0;
37
+ const node_fs_1 = require("node:fs");
38
+ const path = __importStar(require("node:path"));
39
+ const webpack_1 = require("webpack");
40
+ const glass_easel_template_compiler_1 = require("glass-easel-template-compiler");
41
+ const helpers_1 = require("./helpers");
42
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
43
+ const chokidar = require('chokidar');
44
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
45
+ const { RawSource } = require('webpack-sources');
46
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
47
+ const VirtualModulesPlugin = require('webpack-virtual-modules');
48
+ exports.GlassEaselMiniprogramWxmlLoader = path.join(__dirname, 'wxml_loader.js');
49
+ exports.GlassEaselMiniprogramWxssLoader = path.join(__dirname, 'wxss_loader.js');
50
+ const PLUGIN_NAME = 'GlassEaselMiniprogramWebpackPlugin';
51
+ const CACHE_ETAG = 1;
52
+ const readCache = (compiler, key) => new Promise((resolve) => {
53
+ const cacheKey = `${PLUGIN_NAME}|${key}`;
54
+ compiler.cache.get(cacheKey, CACHE_ETAG, (err, cache) => {
55
+ if (!err && cache !== undefined) {
56
+ resolve(cache);
57
+ }
58
+ else {
59
+ resolve(undefined);
60
+ }
61
+ });
62
+ });
63
+ const writeCache = (compiler, key, value) => new Promise((resolve) => {
64
+ const cacheKey = `${PLUGIN_NAME}|${key}`;
65
+ compiler.cache.store(cacheKey, CACHE_ETAG, value, (_err) => {
66
+ resolve();
67
+ });
68
+ });
16
69
  class StyleSheetManager {
17
- constructor() {
18
- this.map = Object.create(null)
19
- this.enableStyleScope = Object.create(null)
20
- this.scopeNameInc = 0
21
- }
22
-
23
- add(compPath, srcPath) {
24
- let scopeNameNum = this.scopeNameInc
25
- this.scopeNameInc += 1
26
- let scopeName = ''
27
- do {
28
- const n = scopeNameNum % 52
29
- let c
30
- if (n >= 26) {
31
- c = String.fromCharCode(n - 26 + 97)
32
- } else {
33
- c = String.fromCharCode(n + 65)
34
- }
35
- scopeName += c
36
- scopeNameNum = Math.floor(scopeNameNum / 52)
37
- } while (scopeNameNum > 0)
38
- this.map[compPath] = {
39
- srcPath,
40
- scopeName,
70
+ constructor(disableClassPrefix) {
71
+ this.map = Object.create(null);
72
+ this.enableStyleScope = Object.create(null);
73
+ this.scopeNameInc = 0;
74
+ this.disableClassPrefix = disableClassPrefix;
41
75
  }
42
- }
43
-
44
- setStyleIsolation(compPath, styleIsolation, isComponent) {
45
- const enabled = styleIsolation
46
- ? styleIsolation !== 'shared' && styleIsolation !== 'page-shared'
47
- : isComponent
48
- this.enableStyleScope[compPath] = enabled
49
- }
50
-
51
- getScopeName(compPath) {
52
- if (this.enableStyleScope[compPath]) {
53
- return this.map[compPath].scopeName
76
+ add(compPath, srcPath) {
77
+ let scopeNameNum = this.scopeNameInc;
78
+ this.scopeNameInc += 1;
79
+ let scopeName = '';
80
+ do {
81
+ const n = scopeNameNum % 52;
82
+ let c;
83
+ if (n >= 26) {
84
+ c = String.fromCharCode(n - 26 + 97);
85
+ }
86
+ else {
87
+ c = String.fromCharCode(n + 65);
88
+ }
89
+ scopeName += c;
90
+ scopeNameNum = Math.floor(scopeNameNum / 52);
91
+ } while (scopeNameNum > 0);
92
+ this.map[compPath] = {
93
+ srcPath,
94
+ scopeName,
95
+ };
54
96
  }
55
- return undefined
56
- }
57
-
58
- toCodeString() {
59
- const arr = Object.entries(this.map).map(([compPath, { srcPath }]) => {
60
- const s = `backend.registerStyleSheetContent('${escapeJsString(
61
- compPath,
62
- )}', require('${escapeJsString(srcPath)}'));`
63
- return s
64
- })
65
- return `
66
- function (backend) { ${arr.join('')} }
67
- `
68
- }
69
- }
70
-
71
- class GlassEaselMiniprogramWebpackPlugin {
72
- constructor(options) {
73
- this.path = options.path || './src'
74
- this.resourceFilePattern = options.resourceFilePattern || /\.(jpg|jpeg|png|gif|html)$/
75
- this.defaultEntry = 'pages/index/index'
76
- this.virtualModules = new VirtualModulesPlugin()
77
- }
78
-
79
- apply(compiler) {
80
- // search paths
81
- const codeRoot = path.resolve(this.path)
82
- const params = {
83
- globalStaticConfig: {},
84
- compInfoMap: Object.create(null),
85
- resPathMap: Object.create(null),
86
- appEntry: null,
87
- tmplGroup: new TmplGroup(),
88
- styleSheetManager: new StyleSheetManager(),
97
+ setStyleIsolation(compPath, styleIsolation, isComponent) {
98
+ const enabled = styleIsolation
99
+ ? styleIsolation !== 'shared' && styleIsolation !== 'page-shared'
100
+ : isComponent;
101
+ this.enableStyleScope[compPath] = enabled;
89
102
  }
90
-
91
- // determine a path is a component path or not, returning the json content if true
92
- const isCompPath = async (relPath) => {
93
- if (!relPath) return null
94
- let staticConfig = null
95
- try {
96
- const json = await fs.readFile(path.join(codeRoot, `${relPath}.json`), { encoding: 'utf8' })
97
- const parsed = JSON.parse(json)
98
- if (parsed && (parsed.component === true || typeof parsed.usingComponents === 'object')) {
99
- staticConfig = parsed
103
+ getScopeName(compPath) {
104
+ var _a;
105
+ if (this.disableClassPrefix)
106
+ return undefined;
107
+ if (this.enableStyleScope[compPath]) {
108
+ return (_a = this.map[compPath]) === null || _a === void 0 ? void 0 : _a.scopeName;
100
109
  }
101
- } catch (e) {
102
- /* empty */
110
+ return undefined;
111
+ }
112
+ toCodeString() {
113
+ const arr = Object.entries(this.map).map(([compPath, { srcPath }]) => {
114
+ const s = `backend.registerStyleSheetContent('${(0, helpers_1.escapeJsString)(compPath)}', require('${(0, helpers_1.escapeJsString)(srcPath)}'));`;
115
+ return s;
116
+ });
117
+ return `
118
+ function (backend) {
119
+ backend.registerStyleSheetContent('app', require('./app.wxss'))
120
+ ${arr.join('')}
103
121
  }
104
- return staticConfig
122
+ `;
105
123
  }
106
-
107
- // determine a file is located in the code root or not, returning relative path if true
108
- const normalizePath = (absPath) => {
109
- const p = path.relative(codeRoot, absPath)
110
- if (p.split(path.sep, 1)[0] === '..') return null
111
- return p.split(path.sep).join('/')
124
+ }
125
+ class GlassEaselMiniprogramWebpackPlugin {
126
+ constructor(options) {
127
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call
128
+ this.virtualModules = new VirtualModulesPlugin();
129
+ this.path = options.path || './src';
130
+ this.resourceFilePattern = options.resourceFilePattern || /\.(jpg|jpeg|png|gif)$/;
131
+ this.defaultEntry = options.defaultEntry || 'pages/index/index';
132
+ this.customBootstrap = options.customBootstrap || false;
133
+ this.disableClassPrefix = options.disableClassPrefix || false;
112
134
  }
113
-
114
- // search for component files
115
- let codeRootPromises = null
116
- const searchCodeRoot = async (enableWatch) => {
117
- if (codeRootPromises) {
118
- // wait a short while for changes
119
- await new Promise((resolve) => {
120
- setTimeout(resolve, 250)
121
- })
122
- const promises = codeRootPromises
123
- codeRootPromises = []
124
- await Promise.all(promises)
125
- return
126
- }
127
- codeRootPromises = []
128
- const handleFile = async (relPath) => {
129
- // for app.json, spread the global field
130
- if (relPath === 'app.json') {
131
- try {
132
- const json = await fs.readFile(path.join(codeRoot, relPath), { encoding: 'utf8' })
133
- const staticConfig = JSON.parse(json)
134
- if (staticConfig.usingComponents) {
135
- params.globalStaticConfig = {
136
- usingComponents: staticConfig.usingComponents,
137
- }
138
- }
139
- } catch (e) {
140
- params.globalStaticConfig = {}
141
- }
142
- return
143
- }
144
-
145
- // for app.ts or app.js, load it first
146
- if (relPath === 'app.ts' || relPath === 'app.js') {
147
- params.appEntry = relPath
148
- }
149
-
150
- // find component by json files
151
- const extName = path.extname(relPath)
152
- if (extName === '.json') {
153
- const staticConfig = await isCompPath(relPath.slice(0, -extName.length))
154
- if (staticConfig) {
155
- const compPath = relPath.slice(0, -5)
135
+ apply(compiler) {
136
+ const codeRoot = path.resolve(this.path);
137
+ const compInfoMap = Object.create(null);
138
+ const resPathMap = Object.create(null);
139
+ const wxmlContentMap = Object.create(null);
140
+ let globalStaticConfig = {};
141
+ let appEntry = null;
142
+ const depsTmplGroup = new glass_easel_template_compiler_1.TmplGroup();
143
+ const styleSheetManager = new StyleSheetManager(this.disableClassPrefix);
144
+ // cleanup wasm modules
145
+ compiler.hooks.shutdown.tap(PLUGIN_NAME, () => {
146
+ depsTmplGroup.free();
147
+ });
148
+ // determine a file is located in the code root or not, returning relative path if true
149
+ const normalizePath = (absPath) => {
150
+ const p = path.relative(codeRoot, absPath);
151
+ if (p.split(path.sep, 1)[0] === '..')
152
+ return null;
153
+ return p.split(path.sep).join('/');
154
+ };
155
+ // determine a path is a component path or not, returning the json content if true
156
+ const isCompPath = (relPath) => __awaiter(this, void 0, void 0, function* () {
157
+ if (!relPath)
158
+ return null;
159
+ let staticConfig = null;
156
160
  try {
157
- const tsFileStat = await fs.stat(path.join(codeRoot, `${compPath}.ts`))
158
- if (tsFileStat.isFile()) {
159
- params.compInfoMap[compPath] = {
160
- main: `${compPath}.ts`,
161
- staticConfig,
161
+ const json = yield node_fs_1.promises.readFile(path.join(codeRoot, `${relPath}.json`), { encoding: 'utf8' });
162
+ const parsed = JSON.parse(json);
163
+ if (parsed && (parsed.component === true || typeof parsed.usingComponents === 'object')) {
164
+ staticConfig = parsed;
162
165
  }
163
- params.styleSheetManager.setStyleIsolation(
164
- compPath,
165
- staticConfig.styleIsolation,
166
- !!staticConfig.component,
167
- )
168
- return
169
- }
170
- } catch (e) {
171
- /* empty */
172
166
  }
173
- try {
174
- const jsFileStat = await fs.stat(path.join(codeRoot, `${compPath}.js`))
175
- if (jsFileStat.isFile()) {
176
- params.compInfoMap[compPath] = {
177
- main: `${compPath}.js`,
178
- staticConfig,
179
- }
180
- return
181
- }
182
- } catch (e) {
183
- /* empty */
167
+ catch (e) {
168
+ /* empty */
184
169
  }
185
- }
186
- }
187
-
188
- // add wxml
189
- if (extName === '.wxml') {
190
- const src = await fs.readFile(path.join(codeRoot, relPath), { encoding: 'utf8' })
191
- params.tmplGroup.addTmpl(relPath.slice(0, -extName.length), src)
192
- // TODO support wxml file remove
193
- }
194
-
195
- // add wxss
196
- if (extName === '.wxss') {
197
- const srcPath = path.join(codeRoot, relPath)
198
- params.styleSheetManager.add(relPath.slice(0, -extName.length), srcPath)
199
- // TODO support wxss file remove
200
- }
201
-
202
- // add wxs
203
- if (extName === '.wxs') {
204
- const src = await fs.readFile(path.join(codeRoot, relPath), { encoding: 'utf8' })
205
- const scriptPath = relPath.slice(0, -extName.length)
206
- params.tmplGroup.addScript(scriptPath, src)
207
- // TODO support wxs file remove
208
- }
209
-
210
- // find resource files
211
- if (this.resourceFilePattern.test(relPath)) {
212
- params.resPathMap[relPath] = true
213
- }
214
- }
215
-
216
- const removeEntry = (relPath) => {
217
- delete params.resPathMap[relPath]
218
- delete params.compInfoMap[relPath]
219
- }
220
-
221
- // await readdirp(codeRoot, handleFile)
222
- await new Promise((resolve, reject) => {
223
- const watcher = chokidar.watch(codeRoot, { ignoreInitial: false })
224
- watcher
225
- .on('add', (p) => {
226
- codeRootPromises.push(handleFile(normalizePath(p)))
227
- })
228
- .on('change', (p) => {
229
- codeRootPromises.push(handleFile(normalizePath(p)))
230
- })
231
- .on('unlink', (p) => {
232
- removeEntry(normalizePath(p))
233
- })
234
- .on('error', (err) => {
235
- throw new Error(err)
236
- })
237
- .on('ready', () => {
238
- const promises = codeRootPromises
239
- codeRootPromises = []
240
- Promise.all(promises)
241
- .then(() => {
242
- if (!enableWatch) return watcher.close()
243
- return null
244
- })
245
- .then(resolve)
246
- .catch(reject)
247
- })
248
- })
249
- }
250
-
251
- // init component list before run
252
- compiler.hooks.beforeRun.tapPromise(PLUGIN_NAME, async () => {
253
- await searchCodeRoot(false)
254
- })
255
- compiler.hooks.watchRun.tapPromise(PLUGIN_NAME, async () => {
256
- await searchCodeRoot(true)
257
- })
258
-
259
- // rewrite component entry paths
260
- compiler.resolverFactory.hooks.resolver.for('normal').tap(PLUGIN_NAME, (resolver) => {
261
- resolver.hooks.result.tap(PLUGIN_NAME, (data) => {
262
- const absPath = data.path
263
- const extName = path.extname(absPath)
264
- if (extName === '.js' || extName === '.ts') {
265
- const relPath = normalizePath(absPath)
266
- if (relPath && params.compInfoMap[relPath.slice(0, -3)]) {
267
- const redirected = `${absPath.slice(0, -3)}.component`
268
- if (data.context.issuer !== redirected) {
269
- data.path = redirected
270
- }
271
- }
272
- }
273
- return data
274
- })
275
- })
276
-
277
- // add loaders
278
- compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
279
- webpack.NormalModule.getCompilationHooks(compilation).beforeLoaders.tap(
280
- PLUGIN_NAME,
281
- (loaders, mod) => {
282
- const absPath = mod.resource
283
- const extName = path.extname(absPath)
284
- if (
285
- extName === '.ts' ||
286
- extName === '.js' ||
287
- extName === '.wxml' ||
288
- extName === '.wxss'
289
- ) {
290
- const relPath = path.relative(codeRoot, absPath).split(path.sep).join('/')
291
- const compPath = relPath.slice(0, -extName.length)
292
- if (params.compInfoMap[compPath] || compPath === 'app') {
293
- if (extName === '.wxss') {
294
- loaders.forEach((x) => {
295
- if (x.loader === GlassEaselMiniprogramWxssLoader) {
296
- x.options = {
297
- classPrefix: params.styleSheetManager.getScopeName(compPath),
298
- relPath,
170
+ return staticConfig;
171
+ });
172
+ // search for component files
173
+ let codeRootWatching = false;
174
+ const searchCodeRoot = (enableWatch) => __awaiter(this, void 0, void 0, function* () {
175
+ if (codeRootWatching)
176
+ return;
177
+ codeRootWatching = true;
178
+ const handleFile = (relPath) => __awaiter(this, void 0, void 0, function* () {
179
+ // for app.json, spread the global field
180
+ if (relPath === 'app.json') {
181
+ try {
182
+ const json = yield node_fs_1.promises.readFile(path.join(codeRoot, relPath), { encoding: 'utf8' });
183
+ const staticConfig = JSON.parse(json);
184
+ if (staticConfig.usingComponents) {
185
+ globalStaticConfig = {
186
+ usingComponents: staticConfig.usingComponents,
187
+ };
188
+ }
189
+ }
190
+ catch (e) {
191
+ globalStaticConfig = {};
192
+ }
193
+ return;
194
+ }
195
+ // for app.ts or app.js, load it first
196
+ if (relPath === 'app.ts' || relPath === 'app.js') {
197
+ appEntry = relPath;
198
+ }
199
+ // find component by json files
200
+ const extName = path.extname(relPath);
201
+ if (extName === '.json') {
202
+ const staticConfig = yield isCompPath(relPath.slice(0, -extName.length));
203
+ if (staticConfig) {
204
+ const compPath = relPath.slice(0, -extName.length);
205
+ const absPath = path.join(codeRoot, `${compPath}.wxss`);
206
+ let hasWxss = false;
207
+ try {
208
+ hasWxss = (yield node_fs_1.promises.stat(absPath)).isFile();
209
+ }
210
+ catch (e) {
211
+ /* empty */
212
+ }
213
+ try {
214
+ const tsFileStat = yield node_fs_1.promises.stat(path.join(codeRoot, `${compPath}.ts`));
215
+ if (tsFileStat.isFile()) {
216
+ compInfoMap[compPath] = {
217
+ main: `${compPath}.ts`,
218
+ taskConfig: staticConfig.taskConfig,
219
+ hasWxss,
220
+ };
221
+ styleSheetManager.add(compPath, absPath);
222
+ styleSheetManager.setStyleIsolation(compPath, staticConfig.styleIsolation, !!staticConfig.component);
223
+ return;
224
+ }
225
+ }
226
+ catch (e) {
227
+ /* empty */
228
+ }
229
+ try {
230
+ const jsFileStat = yield node_fs_1.promises.stat(path.join(codeRoot, `${compPath}.js`));
231
+ if (jsFileStat.isFile()) {
232
+ compInfoMap[compPath] = {
233
+ main: `${compPath}.js`,
234
+ taskConfig: staticConfig.taskConfig,
235
+ hasWxss,
236
+ };
237
+ return;
238
+ }
239
+ }
240
+ catch (e) {
241
+ /* empty */
242
+ }
243
+ }
244
+ }
245
+ // find wxss file for components
246
+ if (extName === '.wxss') {
247
+ const compPath = relPath.slice(0, -5);
248
+ if (compInfoMap[compPath]) {
249
+ compInfoMap[compPath].hasWxss = true;
250
+ }
251
+ }
252
+ // find resource files
253
+ if (this.resourceFilePattern.test(relPath)) {
254
+ resPathMap[relPath] = true;
255
+ }
256
+ });
257
+ const removeEntry = (relPath) => {
258
+ delete resPathMap[relPath];
259
+ const extName = path.extname(relPath);
260
+ const compPath = relPath.slice(0, -extName.length);
261
+ if (compInfoMap[compPath]) {
262
+ if (extName === '.json') {
263
+ delete compInfoMap[compPath];
264
+ }
265
+ else if (extName === '.wxss') {
266
+ compInfoMap[compPath].hasWxss = false;
267
+ }
268
+ }
269
+ };
270
+ // await readdirp(codeRoot, handleFile)
271
+ yield new Promise((resolve, reject) => {
272
+ const promises = [];
273
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call */
274
+ const watcher = chokidar.watch(codeRoot, { ignoreInitial: false });
275
+ watcher
276
+ .on('add', (p) => {
277
+ const normalized = normalizePath(p);
278
+ if (normalized) {
279
+ promises.push(handleFile(normalized));
299
280
  }
300
- }
301
281
  })
302
- } else if (extName === '.wxml' && compPath !== 'app') {
303
- loaders.forEach((x) => {
304
- if (x.loader === GlassEaselMiniprogramWxmlLoader) {
305
- x.options = { compPath }
306
- }
282
+ .on('unlink', (p) => {
283
+ const normalized = normalizePath(p);
284
+ if (normalized)
285
+ removeEntry(normalized);
307
286
  })
308
- }
309
- }
310
- }
311
- },
312
- )
313
- })
314
-
315
- // collect virtual files
316
- const virtualModules = this.virtualModules
317
- virtualModules.apply(compiler)
318
- compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
319
- // add virtual component js file
320
- Object.keys(params.compInfoMap).forEach((compPath) => {
321
- const compInfo = params.compInfoMap[compPath]
322
- const json = JSON.stringify(compInfo.staticConfig)
323
- const scopeName = params.styleSheetManager.getScopeName(compPath)
324
- const scopeNameStr = scopeName === undefined ? undefined : `'${scopeName}'`
325
- virtualModules.writeModule(
326
- path.join(codeRoot, `${compPath}.component`),
287
+ .on('ready', () => {
288
+ Promise.all(promises)
289
+ .then(() => {
290
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
291
+ if (!enableWatch)
292
+ return watcher.close();
293
+ return null;
294
+ })
295
+ .then(resolve)
296
+ .catch(reject);
297
+ });
298
+ /* eslint-enable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call */
299
+ });
300
+ });
301
+ // init component list before run
302
+ compiler.hooks.beforeRun.tapPromise(PLUGIN_NAME, () => __awaiter(this, void 0, void 0, function* () {
303
+ yield searchCodeRoot(false);
304
+ }));
305
+ compiler.hooks.watchRun.tapPromise(PLUGIN_NAME, () => __awaiter(this, void 0, void 0, function* () {
306
+ yield searchCodeRoot(true);
307
+ }));
308
+ // rewrite component entry paths
309
+ compiler.resolverFactory.hooks.resolver.for('normal').tap(PLUGIN_NAME, (resolver) => {
310
+ resolver.hooks.result.tap(PLUGIN_NAME, (data) => {
311
+ var _a;
312
+ if (data.path === false)
313
+ return data;
314
+ const absPath = data.path;
315
+ const extName = path.extname(absPath);
316
+ if (extName === '.js' || extName === '.ts') {
317
+ const relPath = normalizePath(absPath);
318
+ if (relPath && compInfoMap[relPath.slice(0, -3)]) {
319
+ const redirected = `${absPath.slice(0, -3)}.glass-easel-component`;
320
+ if (((_a = data.context) === null || _a === void 0 ? void 0 : _a.issuer) !== redirected) {
321
+ data.path = redirected;
322
+ }
323
+ }
324
+ }
325
+ return data;
326
+ });
327
+ });
328
+ // collect virtual files
329
+ const virtualModules = this.virtualModules;
330
+ virtualModules.apply(compiler);
331
+ compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
332
+ // add loaders
333
+ webpack_1.NormalModule.getCompilationHooks(compilation).beforeLoaders.tap(PLUGIN_NAME, (loaders, mod) => {
334
+ const absPath = mod.resource;
335
+ const extName = path.extname(absPath);
336
+ if (extName === '.wxml' || extName === '.wxss') {
337
+ const relPath = path.relative(codeRoot, absPath).split(path.sep).join('/');
338
+ const compPath = relPath.slice(0, -extName.length);
339
+ if (extName === '.wxss') {
340
+ loaders.forEach((x) => {
341
+ if (x.loader === exports.GlassEaselMiniprogramWxssLoader) {
342
+ x.options = {
343
+ classPrefix: styleSheetManager.getScopeName(compPath),
344
+ relPath,
345
+ };
346
+ }
347
+ });
348
+ }
349
+ else if (extName === '.wxml') {
350
+ loaders.forEach((x) => {
351
+ if (x.loader === exports.GlassEaselMiniprogramWxmlLoader) {
352
+ x.options = {
353
+ addTemplate(content) {
354
+ wxmlContentMap[compPath] = content;
355
+ depsTmplGroup.addTmpl(compPath, content);
356
+ const deps = depsTmplGroup
357
+ .getDirectDependencies(compPath)
358
+ .concat(depsTmplGroup.getScriptDependencies(compPath));
359
+ return {
360
+ compPath,
361
+ deps,
362
+ codeRoot,
363
+ };
364
+ },
365
+ };
366
+ }
367
+ });
368
+ }
369
+ }
370
+ });
371
+ // do some rebuild after all module compilation done
372
+ compilation.hooks.finishModules.tapPromise(PLUGIN_NAME, (modules) => __awaiter(this, void 0, void 0, function* () {
373
+ const tasks = [];
374
+ let indexModule;
375
+ const tmplGroup = new glass_easel_template_compiler_1.TmplGroup();
376
+ // collect compilation results
377
+ // eslint-disable-next-line no-restricted-syntax
378
+ for (const m of modules) {
379
+ if (m.type !== 'javascript/auto')
380
+ continue;
381
+ const module = m;
382
+ if (module.resource === `${codeRoot}/index.js`) {
383
+ indexModule = module;
384
+ continue;
385
+ }
386
+ const absPath = module.resource;
387
+ const extName = path.extname(absPath);
388
+ if (extName === '.wxml') {
389
+ if (module.loaders.some((x) => x.loader === exports.GlassEaselMiniprogramWxmlLoader)) {
390
+ // check wxml results, read cache if needed
391
+ const relPath = path.relative(codeRoot, absPath).split(path.sep).join('/');
392
+ const compPath = relPath.slice(0, -extName.length);
393
+ // eslint-disable-next-line no-loop-func
394
+ tasks.push((() => __awaiter(this, void 0, void 0, function* () {
395
+ let content = wxmlContentMap[compPath];
396
+ if (content) {
397
+ // TODO use compiled content as better cache
398
+ yield writeCache(compiler, relPath, content);
399
+ }
400
+ else {
401
+ const s = yield readCache(compiler, relPath);
402
+ if (s === undefined) {
403
+ throw new Error(`Cannot find WXML compilation result for ${relPath} (webpack cache broken?)`);
404
+ }
405
+ content = s;
406
+ }
407
+ if (typeof content === 'string') {
408
+ tmplGroup.addTmpl(compPath, content);
409
+ }
410
+ }))());
411
+ }
412
+ }
413
+ }
414
+ // write index module
415
+ yield Promise.all(tasks);
416
+ yield new Promise((resolve) => {
417
+ updateVirtualIndexFile(tmplGroup);
418
+ tmplGroup.free();
419
+ compilation.rebuildModule(indexModule, () => resolve());
420
+ });
421
+ }));
422
+ // add virtual component js file
423
+ const updateComponentJsFile = (compPath) => {
424
+ const compInfo = compInfoMap[compPath];
425
+ const scopeName = styleSheetManager.getScopeName(compPath);
426
+ const scopeNameStr = scopeName === undefined ? undefined : `'${scopeName}'`;
427
+ const jsonSrcPath = path.join(codeRoot, `${compPath}.json`);
428
+ const wxmlSrcPath = path.join(codeRoot, `${compPath}.wxml`);
429
+ const wxssSrcPath = path.join(codeRoot, `${compPath}.wxss`);
430
+ const addStyleSheet = compInfo.hasWxss
431
+ ? `
432
+ require('${(0, helpers_1.escapeJsString)(wxssSrcPath)}')
433
+ codeSpace.addStyleSheet(
434
+ '${(0, helpers_1.escapeJsString)(compPath)}',
435
+ '${(0, helpers_1.escapeJsString)(compPath)}',
436
+ ${scopeNameStr}
437
+ )
327
438
  `
328
- var index = require('${escapeJsString(codeRoot)}/index.js')
329
- index.codeSpace.addComponentStaticConfig('${escapeJsString(compPath)}', ${json})
330
- index.codeSpace.addCompiledTemplate('${escapeJsString(compPath)}', {
439
+ : '';
440
+ virtualModules.writeModule(path.join(codeRoot, `${compPath}.glass-easel-component`), `
441
+ var index = require('${(0, helpers_1.escapeJsString)(codeRoot)}/index.js')
442
+ var codeSpace = index.codeSpace
443
+ var staticConfig = require('${(0, helpers_1.escapeJsString)(jsonSrcPath)}')
444
+ staticConfig.usingComponents = Object.assign(
445
+ {},
446
+ index.globalUsingComponents,
447
+ staticConfig.usingComponents
448
+ )
449
+ codeSpace.addComponentStaticConfig('${(0, helpers_1.escapeJsString)(compPath)}', staticConfig)
450
+ codeSpace.addCompiledTemplate('${(0, helpers_1.escapeJsString)(compPath)}', {
331
451
  groupList: index.genObjectGroups,
332
- content: index.genObjectGroups[require(
333
- '${escapeJsString(codeRoot)}/${escapeJsString(compPath)}.wxml'
334
- )]
452
+ content: index.genObjectGroups[require('${(0, helpers_1.escapeJsString)(wxmlSrcPath)}')]
335
453
  })
336
- index.codeSpace.addStyleSheet(
337
- '${escapeJsString(compPath)}',
338
- '${escapeJsString(compPath)}',
339
- ${scopeNameStr}
340
- )
341
- index.codeSpace.globalComponentEnv(index.globalObject, '${escapeJsString(
342
- compPath,
343
- )}', () => {
344
- require('./${escapeJsString(path.basename(compInfo.main))}')
454
+ ${addStyleSheet}
455
+ codeSpace.globalComponentEnv(index.globalObject, '${(0, helpers_1.escapeJsString)(compPath)}', () => {
456
+ require('./${(0, helpers_1.escapeJsString)(path.basename(compInfo.main))}')
345
457
  })
346
- `,
347
- )
348
- })
349
-
350
- // add virtual index file
351
- const entryHeader = `
352
- var adapter = require('glass-easel-miniprogram-adapter')
353
- var glassEasel = adapter.glassEasel
354
- var env = new adapter.MiniProgramEnv()
355
- exports.env = env
356
- var backend = new glassEasel.domlikeBackend.CurrentWindowBackendContext()
357
- backend.onEvent((target, type, detail, options) => {
358
- let cur = target
359
- while (cur && !cur.__wxElement) cur = cur.parentNode
360
- if (!cur) return
361
- glassEasel.triggerEvent(target.__wxElement, type, detail, options)
362
- })
363
- var ab = env.associateBackend(backend)
364
- ;(${params.styleSheetManager.toCodeString()})(ab)
365
- var codeSpace = env.createCodeSpace('', true)
366
- codeSpace.addStyleSheet('app', 'app')
367
- exports.codeSpace = codeSpace
368
- exports.genObjectGroups = ${params.tmplGroup.getTmplGenObjectGroups()}
369
- exports.globalObject = (function () {
370
- if (typeof this !== 'undefined') { return this }
371
- if (typeof globalThis !== 'undefined') { return globalThis }
372
- if (typeof self !== 'undefined') { return self }
373
- if (typeof window !== 'undefined') { return window }
374
- if (typeof global !== 'undefined') { return global }
375
- throw new Error('The global object cannot be recognized')
376
- })()
377
- `
378
- const entryFooter = `
379
- var root = ab.createRoot('glass-easel-root', codeSpace, '${escapeJsString(
380
- this.defaultEntry,
381
- )}')
382
- var placeholder = document.createElement('span')
383
- document.body.appendChild(placeholder)
384
- root.attach(document.body, placeholder)
385
- `
386
- const entries = Object.values(params.compInfoMap).map((compInfo) => compInfo.main)
387
- if (params.appEntry) entries.unshift(params.appEntry)
388
- virtualModules.writeModule(
389
- path.join(codeRoot, 'index.js'),
390
- entryHeader +
391
- entries.map((p) => `require('./${escapeJsString(p)}')\n`).join('') +
392
- entryFooter,
393
- )
394
-
395
- // copy res files
396
- compilation.hooks.additionalAssets.tapPromise(PLUGIN_NAME, async () => {
397
- await Promise.all(
398
- Object.keys(params.resPathMap).map(async (p) => {
399
- compilation.assets[p] = new RawSource(await fs.readFile(path.join(codeRoot, p)))
400
- }),
401
- )
402
- })
403
- })
404
- }
458
+ `);
459
+ };
460
+ Object.keys(compInfoMap).forEach((compPath) => updateComponentJsFile(compPath));
461
+ // add virtual index file
462
+ const updateVirtualIndexFile = (tmplGroup) => {
463
+ const entryHeader = `
464
+ var adapter = require('glass-easel-miniprogram-adapter')
465
+ var glassEasel = adapter.glassEasel
466
+ var env = new adapter.MiniProgramEnv()
467
+ exports.env = env
468
+ var codeSpace = env.createCodeSpace('', true)
469
+ codeSpace.addStyleSheet('app', 'app')
470
+ exports.codeSpace = codeSpace
471
+ exports.genObjectGroups = ${tmplGroup ? tmplGroup.getTmplGenObjectGroups() : '{}'}
472
+ exports.globalUsingComponents = ${JSON.stringify(globalStaticConfig.usingComponents)}
473
+ exports.globalObject = (function () {
474
+ if (typeof this !== 'undefined') { return this }
475
+ if (typeof globalThis !== 'undefined') { return globalThis }
476
+ if (typeof self !== 'undefined') { return self }
477
+ if (typeof window !== 'undefined') { return window }
478
+ if (typeof global !== 'undefined') { return global }
479
+ throw new Error('The global object cannot be recognized')
480
+ })()
481
+ `;
482
+ const entryFooter = `
483
+ var initWithBackend = function (backend) {
484
+ var ab = env.associateBackend(backend)
485
+ ;(${styleSheetManager.toCodeString()})(ab)
486
+ return ab
487
+ }
488
+ exports.initWithBackend = initWithBackend
489
+ var registerGlobalEventListener = function (backend) {
490
+ backend.onEvent((target, type, detail, options) => {
491
+ glassEasel.triggerEvent(target, type, detail, options)
492
+ })
493
+ }
494
+ exports.registerGlobalEventListener = registerGlobalEventListener
495
+ `;
496
+ const bootstrap = this.customBootstrap
497
+ ? ''
498
+ : `
499
+ var backend = new glassEasel.CurrentWindowBackendContext()
500
+ registerGlobalEventListener(backend)
501
+ var ab = initWithBackend(backend)
502
+ var root = ab.createRoot('glass-easel-root', codeSpace, '${(0, helpers_1.escapeJsString)(this.defaultEntry)}')
503
+ var placeholder = document.createElement('span')
504
+ document.body.appendChild(placeholder)
505
+ root.attach(document.body, placeholder)
506
+ `;
507
+ const entries = Object.values(compInfoMap).map((compInfo) => compInfo.main);
508
+ if (appEntry)
509
+ entries.unshift(appEntry);
510
+ virtualModules.writeModule(path.join(codeRoot, 'index.js'), entryHeader +
511
+ entries.map((p) => `require('./${(0, helpers_1.escapeJsString)(p)}')\n`).join('') +
512
+ entryFooter +
513
+ bootstrap);
514
+ };
515
+ updateVirtualIndexFile();
516
+ // copy res files
517
+ compilation.hooks.additionalAssets.tapPromise(PLUGIN_NAME, () => __awaiter(this, void 0, void 0, function* () {
518
+ yield Promise.all(Object.keys(resPathMap).map((p) => __awaiter(this, void 0, void 0, function* () {
519
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
520
+ compilation.assets[p] = new RawSource(yield node_fs_1.promises.readFile(path.join(codeRoot, p)));
521
+ })));
522
+ }));
523
+ });
524
+ }
405
525
  }
406
-
407
- exports.GlassEaselMiniprogramWebpackPlugin = GlassEaselMiniprogramWebpackPlugin
408
- exports.GlassEaselMiniprogramWxmlLoader = GlassEaselMiniprogramWxmlLoader
409
- exports.GlassEaselMiniprogramWxssLoader = GlassEaselMiniprogramWxssLoader
526
+ exports.GlassEaselMiniprogramWebpackPlugin = GlassEaselMiniprogramWebpackPlugin;