-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathindex.js
125 lines (109 loc) · 3.08 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
const path = require('path');
const loaderUtils = require('loader-utils');
const nodeResolve = require('resolve').sync;
const walk = require('pug-walk');
/*
* Enusre pug and runtime are from same version
*/
const pugPath = require.resolve('pug');
const pug = require(pugPath);
const runtimePath = nodeResolve('pug-runtime', {
basedir: path.dirname(pugPath)
});
module.exports = function (source) {
/*
* All the cool loaders do it
*/
if (this.cacheable) this.cacheable(true);
/*
* Options and context
*/
const loaderContext = this;
const options = loaderUtils.getOptions(this) || {};
const filename = loaderContext.resourcePath;
let func;
source = typeof source === 'string' ? source : source.toString();
/*
* The plugin is hooked into right before pug "links" the included files,
* which means right before it inlines the included file content into the
* template. Here, we remove raw includes and replace them with
* "- require("path/to/include.notpug")
*/
const plugin = {
preLink(ast) {
return walk(ast, (node, replace) => {
if (
node.type === 'RawInclude' &&
node.file &&
path.extname(node.file.fullPath) !== '.pug'
) {
const val = `require(${loaderUtils.stringifyRequest(
loaderContext,
node.file.fullPath
)})`;
replace({
type: 'Code',
val,
buffer: true,
mustEscape: false,
isInline: false,
line: node.line,
filename: node.filename
});
}
});
}
};
try {
const pugOptions = {
filename,
doctype: options.doctype || 'html',
pretty: options.pretty,
self: options.self,
compileDebug: loaderContext.debug || false,
globals: ['require'].concat(options.globals || []),
name: 'template',
inlineRuntimeFunctions: false,
filters: options.filters,
plugins: [plugin].concat(options.plugins || []),
basedir: options.root || options.basedir
};
/*
* Compile the pug
*/
const compilation = pug.compileClientWithDependenciesTracked(
source,
pugOptions
);
func = compilation.body;
/*
* Let webpack know to watch the dependencies
*/
if (compilation.dependencies && compilation.dependencies.length > 0)
for (const dep of compilation.dependencies)
loaderContext.addDependency(dep);
} catch (error) {
/*
* Catch errors if needed
*/
/*
* Add the file where the error occurred as a dependency
*/
loaderContext.addDependency(path.normalize(error.filename));
loaderContext.callback(error);
return;
}
/*
* Add the runtime dependency
*/
const requireRuntimeString =
'var pug = require(' +
loaderUtils.stringifyRequest(loaderContext, '!' + runtimePath) +
');\n\n';
const compiled =
requireRuntimeString + func + '\n\nmodule.exports = template';
/*
* Return the compiled function to be processes as a JS module now
*/
loaderContext.callback(null, compiled);
};