Haskel programs have one property. After compilation, we get a self-contained binary, one file with executable machine code. Languages with compilers, convenient for web development, not so much. This property has no special significance. However, it allows you to achieve unsurpassed ease of installing programs. And not only the installation, but all that is hidden behind the English word
deployment .
Web applications use additional data - images, css styles, javascript scripts. As a rule, they are stored separately from the executable code of the application in the file system of the web server. But if these additional resources are less than a megabyte - why not embed them directly into the binary? Making web application deployment easier!
This article continues the
theme of a small but interesting project
iptadmin .
Embedding
Embedding text into an executable file is a simple task. It is enough to create a string constant. Embedding binary files in an executable file is a bit more complicated.
')
In
hackage , a
file-embed library from the
author of the web-framework
yesod was found .
This library, using the
ghc template haskell extension, reads arbitrary files at compile time, converts them to strings, saves to string constants and provides an interface to them as to byte strings. String characters with codes outside the printable range are saved without problems. As with this approach, they do not participate in the input / output and are not displayed in the code editor.
The author of the library suggests using the
embedDir function. It retrieves a list of files from the specified directory, and creates a list of pairs (Filename, Byte string) for convenient processing of a large set of files.
But still, the
embedFile function was used, it is called for each file separately (
PageHandlers function ). This increased the amount of code, but gave confidence that if the program was compiled, then all the files are definitely there. The number of tests required has decreased.
Access to resources
Url to access the "static" data is left unchanged. Therefore, in the client part of the application did not have to edit anything. The http root directory of the / static server is processed by a separate handler. The handler is called at the beginning of the authorization function (
authorize ). Before the authorization procedure, the login page works correctly.
It is quite simple to give the client a file using the ByteString in
Happstack . You can lapidably collect a
Response value using the Response data constructor. In the rsHeaders field, add a header with Content-Type, in the rsBody field, specify our saved ByteString.
However, the Happstack.Server.FileServe.BuildingBlocks module appeared in Happstack 6, which does exactly what you need. The
strictByteSTringResponse function accepts a ByteString input, a Content-Type description, and returns a file to the client. This feature has been used. To transfer different types of files to the
client, the returnJs, returnCss, and returnPng functions are written.
304
“Large” web servers support
conditional GET requests with If-Modified-Since headers, and if the requested file has not changed since the last access, return code
304 with an empty message-body. This method speeds up web applications and reduces network traffic.
Answer client code 304 for already loaded resources necessary. In the case of assembling a response to a client manually, using the Response constructor, you would also need to manually analyze the request and verify that the data has not changed since the last request. The functions of the Happstack.Server.FileServe.BuildingBlocks module implement this functionality “under the hood”. It is only necessary to transmit the date and time of the data change.
Where to get this date? Obviously, in our case, the time of the last change of the “file” will be the compilation time of the application. Therefore, we will get it in the compilation process using template haskell (
updateTime ).
Problems and Solutions
This approach has several obvious problems.
When changing only static files, the build system does not rebuild the Static module. Therefore, to force a rebuild, you need to run the
touch Static.hs command , and then build it. The
htmlrebuild command has been added to automate the Makefile.
In addition, the development cycle is significantly increased. After editing the javascript program, you need to completely rebuild the application's Static module. Then run it, and only after that you can start debugging. This question is solved simply, at the time of development you need to enable access through the / static directory to files in the file system. How this is done in all web applications. By means of happstack this is done trivially. And only during the assembly of the finished release to embed resources in the executable file.
ps
As usual, I will be glad to criticism and any other feedback.
If someone suddenly accidentally post on this topic seemed interesting, suggest interesting topics for future posts. If there is no account on this great site, there are other ways to contact.