glass-easel-miniprogram-webpack-plugin 0.2.0 → 0.3.0

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