UNPKG

5.48 kBJavaScriptView Raw
1const path = require('path')
2
3let config = require('./config')
4const utils = require('./utils')
5const parse = require('./parser/parse')
6
7const state = {
8
9 mode: null,
10 proc: null,
11
12 config,
13
14 entries: [],
15 deps: [],
16
17 rootPath: null,
18 exclude: null,
19 clientRoot: '.',
20
21}
22
23const cache = []
24
25
26async function init(mode, root, options) {
27 state.mode = mode
28 state.proc = config[mode]
29
30 let userConfig = {}
31 try {
32 userConfig = require(path.resolve('webo.config.js'))
33 merge(config, userConfig)
34 } catch (error) { }
35
36 if (root) config.srcRoot = root
37 state.rootPath = path.join(path.resolve('.'), config.srcRoot)
38 state.exclude = [...config.exclude, config.destRoot + '/**']
39 await resolveLayout()
40
41 merge(state, options)
42 let discoveredEntries = await utils.globAsync('**/*.html', { cwd: '.', nodir: true, ignore: state.exclude })
43 // console.log(discoveredEntries)
44 state.entries = [... new Set(discoveredEntries)]
45
46 await Promise.all(state.entries.filter(o => !o.endsWith('_layout.html')).map(loadFile))
47 // console.log('***', state.entries, state.deps.length)
48}
49
50
51
52async function loadFile(filename, type) {
53 if (filename.endsWith('.html')) {
54 if (!state.entries.includes(filename)) state.entries.push(filename)
55 }
56 const { deps } = await parse(filename, state.mode, type)
57// if (filename.endsWith('client/index.html')) console.log(filename, deps)
58 await Promise.all(
59 deps.filter(dep => !state.deps.find(o => o.path === dep.path && o.ref === dep.ref)).map(async dep => {
60 state.deps.push(dep)
61 await loadFile(dep.path, dep.type)
62 })
63 )
64}
65
66// async function updateEntry(filename, recursive) {
67// if (!state.entries.includes(filename)) {
68// state.entries.push(filename)
69// }
70// const { deps } = await parse(filename, 'dev', recursive)
71// console.log(filename, deps.length)
72// deps.forEach(attachDep)
73// }
74
75async function removeEntry(filename) {
76 state.entries.splice(state.entries.indexOf(filename), 1)
77 state.deps = state.deps.filter(o => o.root !== filename)
78}
79
80function attachDep(dep) {
81 const existingIndex = state.deps.findIndex(o => o.path === dep.path)
82 existingIndex === -1 ? state.deps.push(dep) : state.deps.splice(existingIndex, 1, dep)
83}
84
85
86
87
88
89
90
91async function createDep(referrer, rel, type, root) {
92 // const { state } = require('../state')
93 if (rel.startsWith('http://') || rel.startsWith('https://')) return null
94 let depPath
95 if (rel.startsWith('/')) {
96 depPath = state.config.srcRoot + rel
97 } else {
98 depPath = path.relative('.' , path.resolve(path.dirname(referrer), rel.split('?')[0])).replace(/\\/g, '/')
99 }
100 let dep = {
101 path: depPath,
102 get pathHashed() {
103 if (!this.hash) return this.rel
104 const parts = this.path.split('.')
105 if (parts.length > 1) {
106 parts[parts.length - 2] += '-' + this.hash
107 return parts.join('.')
108 }
109 },
110 ref: referrer,
111 rel,
112 get relHashed() {
113 if (!this.hash) return this.rel
114 const relParts = this.rel.split('.')
115 if (relParts.length > 1) {
116 relParts[relParts.length - 2] += '-' + this.hash
117 // dep.rel = relParts.join('.')
118 return relParts.join('.')
119 }
120 },
121 type,
122 root,
123 }
124 if (state.proc.hash) dep.hash = await utils.calcHash(depPath)
125 // if (state.proc.hash) {
126 // const relParts = dep.rel.split('.')
127 // if (relParts.length > 1) {
128 // relParts[relParts.length - 2] += '-' + (await utils.calcHash(depPath))
129 // // dep.rel = relParts.join('.')
130 // dep.relHashed = relParts.join('.')
131 // }
132 // }
133 return dep
134}
135
136
137function setDep(dep) {
138 const index = state.deps.findIndex(o => o.ref === dep.ref && o.path === dep.path)
139 if (index !== -1) {
140 state.deps.slice(index, 1, dep)
141 } else {
142 state.deps.push(dep)
143 }
144}
145
146
147
148
149
150function merge(dest = {}, src) {
151 for (const prop in src) {
152 if (!dest[prop] || !dest.hasOwnProperty(prop)) { dest[prop] = src[prop]; continue; }
153 if (Array.isArray(dest[prop]) && Array.isArray(src[prop])) { dest[prop].push(... src[prop]); dest[prop] = [... new Set(dest[prop])]; continue; }
154 if (typeof dest[prop] === 'object') { merge(dest[prop], src[prop]); continue; }
155 dest[prop] = src[prop]
156 }
157}
158
159async function resolveLayout() {
160 let layoutPath = state.config.layout || (await utils.globAsync('**/_layout.html', { cwd: '.', nodir: true, ignore: state.exclude }))[0]
161 if (!layoutPath) return
162 try {
163 await utils.readFileAsync(layoutPath)
164 state.config.layout = layoutPath
165 console.log(`using layout file ${state.config.layout}`)
166 } catch (error) {
167 if (layoutPath) console.error(`layout file not found ${layoutPath}`)
168 if (state.config.layout) process.exit()
169 }
170
171
172
173 // if (state.config.layout) {
174 // try {
175 // await utils.readFileAsync(state.config.layout)
176 // } catch (error) {
177 // console.error(`layout file not found ${state.config.layout}`)
178 // }
179 // } else {
180 // try {
181 // await utils.readFileAsync(state.config.srcRoot + '/_layout.html')
182 // state.config.layout = state.config.srcRoot + '/_layout.html'
183 // console.log(`using layout file ${state.config.layout}`)
184 // } catch (error) { }
185 // }
186}
187
188
189module.exports = {
190 state,
191 cache,
192 init,
193 loadFile,
194 // updateEntry,
195 removeEntry,
196 setDep,
197 createDep,
198}