1 | const URL = require('url');
|
2 | const path = require('path');
|
3 | const fs = require('./utils/fs');
|
4 | const objectHash = require('./utils/objectHash');
|
5 | const md5 = require('./utils/md5');
|
6 | const isURL = require('./utils/is-url');
|
7 | const config = require('./utils/config');
|
8 |
|
9 | let ASSET_ID = 1;
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 | class Asset {
|
18 | constructor(name, pkg, options) {
|
19 | this.id = ASSET_ID++;
|
20 | this.name = name;
|
21 | this.basename = path.basename(this.name);
|
22 | this.relativeName = path.relative(options.rootDir, this.name);
|
23 | this.package = pkg || {};
|
24 | this.options = options;
|
25 | this.encoding = 'utf8';
|
26 | this.type = path.extname(this.name).slice(1);
|
27 |
|
28 | this.processed = false;
|
29 | this.contents = options.rendition ? options.rendition.value : null;
|
30 | this.ast = null;
|
31 | this.generated = null;
|
32 | this.hash = null;
|
33 | this.parentDeps = new Set();
|
34 | this.dependencies = new Map();
|
35 | this.depAssets = new Map();
|
36 | this.parentBundle = null;
|
37 | this.bundles = new Set();
|
38 | this.cacheData = {};
|
39 | this.buildTime = 0;
|
40 | this.bundledSize = 0;
|
41 | }
|
42 |
|
43 | shouldInvalidate() {
|
44 | return false;
|
45 | }
|
46 |
|
47 | async loadIfNeeded() {
|
48 | if (this.contents == null) {
|
49 | this.contents = await this.load();
|
50 | }
|
51 | }
|
52 |
|
53 | async parseIfNeeded() {
|
54 | await this.loadIfNeeded();
|
55 | if (!this.ast) {
|
56 | this.ast = await this.parse(this.contents);
|
57 | }
|
58 | }
|
59 |
|
60 | async getDependencies() {
|
61 | if (
|
62 | this.options.rendition &&
|
63 | this.options.rendition.hasDependencies === false
|
64 | ) {
|
65 | return;
|
66 | }
|
67 |
|
68 | await this.loadIfNeeded();
|
69 |
|
70 | if (this.contents && this.mightHaveDependencies()) {
|
71 | await this.parseIfNeeded();
|
72 | await this.collectDependencies();
|
73 | }
|
74 | }
|
75 |
|
76 | addDependency(name, opts) {
|
77 | this.dependencies.set(name, Object.assign({name}, opts));
|
78 | }
|
79 |
|
80 | addURLDependency(url, from = this.name, opts) {
|
81 | if (!url || isURL(url)) {
|
82 | return url;
|
83 | }
|
84 |
|
85 | if (typeof from === 'object') {
|
86 | opts = from;
|
87 | from = this.name;
|
88 | }
|
89 |
|
90 | const parsed = URL.parse(url);
|
91 | const resolved = path.resolve(path.dirname(from), parsed.pathname);
|
92 | this.addDependency(
|
93 | './' + path.relative(path.dirname(this.name), resolved),
|
94 | Object.assign({dynamic: true}, opts)
|
95 | );
|
96 |
|
97 | parsed.pathname = this.options.parser
|
98 | .getAsset(resolved, this.package, this.options)
|
99 | .generateBundleName();
|
100 |
|
101 | return URL.format(parsed);
|
102 | }
|
103 |
|
104 | async getConfig(filenames, opts = {}) {
|
105 |
|
106 | let conf = await config.resolve(opts.path || this.name, filenames);
|
107 | if (conf) {
|
108 |
|
109 |
|
110 | this.addDependency(conf, {includedInParent: true});
|
111 | if (opts.load === false) {
|
112 | return conf;
|
113 | }
|
114 |
|
115 | return await config.load(opts.path || this.name, filenames);
|
116 | }
|
117 |
|
118 | return null;
|
119 | }
|
120 |
|
121 | mightHaveDependencies() {
|
122 | return true;
|
123 | }
|
124 |
|
125 | async load() {
|
126 | return await fs.readFile(this.name, this.encoding);
|
127 | }
|
128 |
|
129 | parse() {
|
130 |
|
131 | }
|
132 |
|
133 | collectDependencies() {
|
134 |
|
135 | }
|
136 |
|
137 | async pretransform() {
|
138 |
|
139 | }
|
140 |
|
141 | async transform() {
|
142 |
|
143 | }
|
144 |
|
145 | async generate() {
|
146 | return {
|
147 | [this.type]: this.contents
|
148 | };
|
149 | }
|
150 |
|
151 | async process() {
|
152 | if (!this.generated) {
|
153 | await this.loadIfNeeded();
|
154 | await this.pretransform();
|
155 | await this.getDependencies();
|
156 | await this.transform();
|
157 | this.generated = await this.generate();
|
158 | this.hash = await this.generateHash();
|
159 | }
|
160 |
|
161 | return this.generated;
|
162 | }
|
163 |
|
164 | async postProcess(generated) {
|
165 | return generated;
|
166 | }
|
167 |
|
168 | generateHash() {
|
169 | return objectHash(this.generated);
|
170 | }
|
171 |
|
172 | invalidate() {
|
173 | this.processed = false;
|
174 | this.contents = null;
|
175 | this.ast = null;
|
176 | this.generated = null;
|
177 | this.hash = null;
|
178 | this.dependencies.clear();
|
179 | this.depAssets.clear();
|
180 | }
|
181 |
|
182 | invalidateBundle() {
|
183 | this.parentBundle = null;
|
184 | this.bundles.clear();
|
185 | this.parentDeps.clear();
|
186 | }
|
187 |
|
188 | generateBundleName() {
|
189 |
|
190 |
|
191 | return md5(this.name) + '.' + this.type;
|
192 | }
|
193 |
|
194 | replaceBundleNames(bundleNameMap) {
|
195 | for (let key in this.generated) {
|
196 | let value = this.generated[key];
|
197 | if (typeof value === 'string') {
|
198 |
|
199 | for (let [name, map] of bundleNameMap) {
|
200 | value = value.split(name).join(map);
|
201 | }
|
202 |
|
203 | this.generated[key] = value;
|
204 | }
|
205 | }
|
206 | }
|
207 |
|
208 | generateErrorMessage(err) {
|
209 | return err;
|
210 | }
|
211 | }
|
212 |
|
213 | module.exports = Asset;
|