UNPKG

8.38 kBJavaScriptView Raw
1var path = require('path')
2var fs = require('fs-extra')
3var terraform = require('terraform')
4var async = require('async')
5var connect = require('connect')
6var mime = require('mime-types')
7var helpers = require('./helpers')
8var middleware = require('./middleware')
9var pkg = require('../package.json')
10var url = require("url")
11
12
13
14/**
15 * Server
16 *
17 * Host a single Harp application.
18 *
19 */
20
21exports.server = function(dirPath, options, callback){
22 var app = connect()
23 app.use(middleware.regProjectFinder(dirPath))
24 app.use(middleware.setup)
25 app.use(middleware.basicAuth)
26 app.use(middleware.underscore)
27
28 // app.use(function(req, rsp, next){
29 // var pathname = url.parse(req.url).pathname.replace(/^\/|\/$/g, '')
30 // if (pathname !== "app.js") return next()
31 // var setup = helpers.setup(dirPath)
32 // var results = esbuild.buildSync({
33 // absWorkingDir: setup.publicPath,
34 // entryPoints: [setup.publicPath + '/app.jsx'],
35 // outfile: 'app.js',
36 // bundle: true,
37 // write: false,
38 // plugins: [],
39 // })
40 // rsp.statusCode = 200
41 // rsp.end(results.outputFiles[0]["text"])
42 // })
43
44 // app.use(function(req, rsp, next){
45 // var pathname = url.parse(req.url).pathname.replace(/^\/|\/$/g, '')
46 // if (pathname !== "bundle.js") return next()
47 // var setup = helpers.setup(dirPath)
48 // var results = esbuild.buildSync({
49 // absWorkingDir: setup.publicPath,
50 // entryPoints: [setup.publicPath + '/bundle.cjs'],
51 // outfile: 'bundle.js',
52 // bundle: true,
53 // write: false,
54 // plugins: [],
55 // })
56 // rsp.statusCode = 200
57 // rsp.end(results.outputFiles[0]["text"])
58 // })
59
60 app.use(middleware.mwl)
61 app.use(middleware.static)
62 app.use(middleware.poly)
63 app.use(middleware.process)
64 app.use(middleware.fallback2)
65
66 return app
67
68 // return app.listen(options.port || 9966, options.ip, function(){
69 // app.projectPath = dirPath
70 // callback.apply(app, arguments)
71 // })
72}
73
74
75/**
76 * Multihost
77 *
78 * Host multiple Harp applications.
79 *
80 */
81
82exports.multihost = function(dirPath, options, callback){
83 var app = connect()
84 app.use(middleware.notMultihostURL)
85 app.use(middleware.index(dirPath))
86 app.use(middleware.hostProjectFinder(dirPath))
87 app.use(middleware.setup)
88 app.use(middleware.basicAuth)
89 app.use(middleware.underscore)
90 app.use(middleware.mwl)
91 app.use(middleware.static)
92 app.use(middleware.poly)
93 app.use(middleware.process)
94 app.use(middleware.fallback2)
95 app.listen(options.port || 9000, callback)
96}
97
98/**
99 * Mount
100 *
101 * Offer the asset pipeline as connect middleware
102 *
103 */
104
105exports.mount = function(mountPoint, root){
106
107 if(!root){
108 root = mountPoint
109 mountPoint = null
110 }else{
111 var rx = new RegExp("^" + mountPoint)
112 }
113
114 var finder = middleware.regProjectFinder(root)
115
116 return function(req, rsp, next){
117
118 if(rx){
119 if(!req.url.match(rx)) return next()
120 var originalUrl = req.url
121 req.url = req.url.replace(rx, "/")
122 }
123
124 finder(req, rsp, function(){
125 middleware.setup(req, rsp, function(){
126 middleware.static(req, rsp, function(){
127 middleware.poly(req, rsp, function(){
128 middleware.process(req, rsp, function(){
129 if(originalUrl) req.url = originalUrl
130 next()
131 })
132 })
133 })
134 })
135 })
136 }
137}
138
139
140/**
141 * Pipeline
142 *
143 * Offer the asset pipeline as connect middleware
144 *
145 */
146
147exports.pipeline = function(root){
148 console.log("Deprecated, please use MOUNT instead, this will be removed in a future version.");
149 var publicPath = path.resolve(root)
150 var terra = terraform.root(publicPath)
151
152 return function(req, rsp, next){
153 var normalizedPath = helpers.normalizeUrl(req.url)
154 var priorityList = terraform.helpers.buildPriorityList(normalizedPath)
155 var sourceFile = terraform.helpers.findFirstFile(publicPath, priorityList)
156
157 if(!sourceFile) return next()
158
159 terra.render(sourceFile, function(error, body){
160 if(error) return next(error)
161 if(!body) return next() // 404
162
163 var outputType = terraform.helpers.outputType(sourceFile)
164 var mimeType = helpers.mimeType(outputType)
165 var charset = mime.charsets.lookup(mimeType)
166 rsp.statusCode = 200
167 rsp.setHeader('Content-Type', mimeType + (charset ? '; charset=' + charset : ''))
168 rsp.setHeader('Content-Length', Buffer.byteLength(body, charset));
169 rsp.end(body)
170 })
171
172 }
173
174}
175
176exports.pkg = pkg
177
178/**
179 * Export middleware
180 *
181 * Make sure middleware is accessible
182 * when using harp as a library
183 *
184 */
185exports.middleware = middleware;
186
187/**
188 * Compile
189 *
190 * Compiles Single Harp Application.
191 *
192 */
193
194exports.compile = function(projectPath, outputPath, callback){
195
196 /**
197 * Both projectPath and outputPath are optional
198 */
199
200 if(!callback && typeof outputPath === "function"){
201 callback = outputPath
202 outputPath = "www"
203 }
204
205 if(!outputPath){
206 outputPath = "www"
207 }
208
209
210 /**
211 * Setup all the paths and collect all the data
212 */
213
214 try{
215 outputPath = path.resolve(projectPath, outputPath)
216 var setup = helpers.setup(projectPath, "production")
217 var terra = terraform.root(setup.publicPath, setup.config.globals)
218 }catch(err){
219 return callback(err)
220 }
221
222
223 /**
224 * Protect the user (as much as possible) from compiling up the tree
225 * resulting in the project deleting its own source code.
226 */
227
228 if(!helpers.willAllow(projectPath, outputPath)){
229 return callback({
230 type: "Invalid Output Path",
231 message: "Output path cannot be greater then one level up from project path and must be in directory starting with `_` (underscore).",
232 projectPath: projectPath,
233 outputPath: outputPath
234 })
235 }
236
237
238 /**
239 * Compile and save file
240 */
241
242 var compileFile = function(file, done){
243 process.nextTick(function () {
244 terra.render(file, function(error, body){
245 if(error){
246 done(error)
247 }else{
248 if(body){
249 var dest = path.resolve(outputPath, terraform.helpers.outputPath(file))
250 fs.mkdirp(path.dirname(dest), function(err){
251 fs.writeFile(dest, body, done)
252 })
253 }else{
254 if (file === "app.jsx"){
255 var results = esbuild.buildSync({
256 absWorkingDir: setup.publicPath,
257 entryPoints: [setup.publicPath + '/app.jsx'],
258 outfile: 'app.js',
259 bundle: true,
260 write: false,
261 plugins: [],
262 })
263 fs.writeFile([outputPath, "app.js"].join(path.sep), results.outputFiles[0]["text"], done)
264 }else if (file === "bundle.cjs"){
265 var results = esbuild.buildSync({
266 absWorkingDir: setup.publicPath,
267 entryPoints: [setup.publicPath + '/bundle.cjs'],
268 outfile: 'bundle.js',
269 bundle: true,
270 write: false,
271 plugins: [],
272 })
273 fs.writeFile([outputPath, "bundle.js"].join(path.sep), results.outputFiles[0]["text"], done)
274 } else {
275 done()
276 }
277 }
278 }
279 })
280 })
281 }
282
283
284 /**
285 * Copy File
286 *
287 * TODO: reference ignore extensions from a terraform helper.
288 */
289 var copyFile = function(file, done){
290 var ext = path.extname(file)
291 if(!terraform.helpers.shouldIgnore(file) && [".jsx", ".jade", ".ejs", ".md", ".styl", ".less", ".scss", ".sass", ".coffee", ".cjs"].indexOf(ext) === -1){
292 var localPath = path.resolve(outputPath, file)
293 fs.mkdirp(path.dirname(localPath), function(err){
294 fs.copy(path.resolve(setup.publicPath, file), localPath, done)
295 })
296 }else{
297 done()
298 }
299 }
300
301 /**
302 * Scan dir, Compile Less and Jade, Copy the others
303 */
304
305 helpers.prime(outputPath, { ignore: projectPath }, function(err){
306 if(err) console.log(err)
307
308 helpers.ls(setup.publicPath, function(err, results){
309 async.each(results, compileFile, function(err){
310 if(err){
311 callback(err)
312 }else{
313 async.each(results, copyFile, function(err){
314 setup.config['harp_version'] = pkg.version
315 delete setup.config.globals
316 callback(null, setup.config)
317 })
318 }
319 })
320 })
321 })
322
323}