lukejacksonn / servor Goto Github PK
View Code? Open in Web Editor NEWDependency free file server for single page app development
License: MIT License
Dependency free file server for single page app development
License: MIT License
Hey.
I'm using Servor to serve an SPA with create-react-app
The problem is - whenever my SPA route ends with a slash I have 404.
For example, let's say I'm serving my app from https://myapp.com
, and I have a react route /hello-world
.
This URL works fine https://myapp.com/hello-world
But this one gives me 404 https://myapp.com/hello-world/
I'm trying to install the certs so that I won't see the "
I ran sudo npm i -g servor
then sudo servor --secure
, and it threw and error saying
(node:4316) UnhandledPromiseRejectionWarning: Error: EACCES: permission denied, uv_cwd
at module.exports (/Users/me/.nvm/versions/node/v10.20.1/lib/node_modules/servor/servor.js:38:58)
at process._tickCallback (internal/process/next_tick.js:68:7)
at Function.Module.runMain (internal/modules/cjs/loader.js:834:11)
at startup (internal/bootstrap/node.js:283:19)
at bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)
(node:4316) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
(node:4316) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
I'm on macOS Catalina 10.15.5 (19F96).
npm -v
6.14.4
node -v
v10.20.1
servor
4.0.2
Hey mate, I've been running into a couple issues with how Chrome handles media (audio/video):
Without the response header Content-Length
, checking media.duration
returns Infinity
.
Without serving the requested chunk (Content-Range
), changing media.currentTime
just makes the file play from the beginning (as the whole file is returned).
In comparison, Firefox has neither issue.
I recall reading about this a long time ago, and found it weird how Chrome kept re-downloading the video assets with experiences that involve changing the currentTime, but I'm not sure how best to work streaming into Servor. Any ideas/thoughts?
Cheers.
I know this project comes with no dependencies at the moment, but having static typing is very important to me.
Flowtype is a nice fit for this project since flow-remove-type
is a very simple tool.
I have a fork which adds support for flow: master...taylorgoolsby:master
If you still want to keep no dependencies, how do you feel about implementing a hook/plugin system? I have something like this in mind:
// Add `transform` as a parameter to `servor`:
module.exports = async ({
root = '.',
module = false,
fallback = module ? 'index.js' : 'index.html',
reload = true,
static = false,
inject = '',
credentials,
port,
transform
} = {}) => {
// sendFile passes files through `transform`:
const sendFile = (res, status, file, ext, encoding = 'binary') => {
if (transform) {
file = transform(file, ext)
}
if (['js', 'css', 'html', 'json', 'xml', 'svg'].includes(ext)) {
res.setHeader('content-encoding', 'gzip');
file = zlib.gzipSync(utf8(file));
encoding = 'utf8';
}
res.writeHead(status, { 'content-type': mimeTypes(ext) });
res.write(file, encoding);
res.end();
};
// flowtype + servor using the transform plugin:
const flowRemoveTypes = require('flow-remove-types');
const servor = require('servor');
const instance = await servor({
root: '.',
fallback: 'index.html',
module: false,
static: false,
reload: false,
inject: '',
credentials: null,
port: 8080,
transform: (file, ext) => {
if (ext === 'js') {
file = flowRemoveTypes(file).toString()
}
return file
}
});
I appreciate the simplicity of the command without too many flags, but I change the port much often than I change the fallback file. In fact, I've never changed the fallback file π
Would love to see --port
so I can do yarn servor dist --port 3001
instead of yarn servor dist dist/index.html 3001
.
Not sure if I'm doing something wrong, but...
Running the server with this
$ yarn http-server-spa . index.html
in a simple folder with an index.html
that points to index.js
, the following work as expected.
http://localhost:8080/
http://localhost:8080/foo
However, this one breaks.
http://localhost:8080/foo/bar
The error:
GET http://localhost:8080/foo/index.js 404 (Not Found)
Here's the console output since running, through all steps above, until the last one.
----------------------------------------------
[OK] Serving static files from ./.
[OK] Using the fallback file index.html
[OK] Listening on http://localhost:8080
----------------------------------------------
[OK] GET /foo/bar
[ER] GET /foo/index.js
[OK] GET /
[OK] GET /index.js
[OK] GET /foo
[OK] GET /index.js
[OK] GET /foo/bar
[ER] GET /foo/index.js
Consider the following project tree:
project-root
β src
β β main.js
β static
β index.html
Currently, for index.html
be able to link to main.js
, servor must run in the project-root
folder and the script tag in html must be <script src="../src/main.js">
$ cd ~/project-root
$ servor .
It would be really useful to allow servor to serve more folders than just the root. Something like:
$ cd ~/project-root
$ servor ./static --extern ./src
This would serve the ./src
folder as if it and ./static
were the same.
So the index.html
would link the script at same level (<script src="./main.js">
)
The --extern
param could be repeatable to allow multiple entrypoints
$ cd ~/project-root
$ servor ./static --extern ./src --extern ./libs
Duplicate paths (e.g.: ./static/style.css
, ./src/style.css
and ./libs/style.css
) could be served in order (left-to-right), returning the first found path.
Each served html should have livereloading functional. For now it works only for index.html
files.
To use servor livereload feature not only for spa, but for traditional sites as well.
I believe this should work as default, but it could be opt-in.
I found only one way to achieve this - place separate index.html
into nested directories (one dir per html), link them with /nested_dir
and run servor with servor --reload --static
I have an app.js
with the following code:
button('β΅', { onclick: props.play }),
in the browser it gets received as:
button('Γ’οΏ½Β΅', { onclick: props.play }),
Same issue with another lib: mjackson/history-server#3
Works fine with https://github.com/indexzero/http-server
Running servor crashes the st terminal in Ubuntu 20.10
https://st.suckless.org/
This is probably firefox issue (or even just me). But maybe is it related to servor configuration?
servor --reload
, open it in FFAdditional info:
Firefox 89.0.1, Win 8.1
Tested in Chromium 88.0.4324.150 and there is no problem. There is also no problem in Firefox if I run servor
without --reload
flag and do reload with F5.
With the new version when I reload a custom route (for example /profile
) servor injects a <meta charset="UTF-8" > and a
` tags at the start of my index.html, so my files are not found because they expect that base has to be "/".
Can I use any option to disable this behavior?
Hi,
afaict, servor does not return etag or last-modified headers. It would be great if this could be added.
Thanks
Hi @lukejacksonn, first off, thank you so much for putting this together.
While using servor
for my prototype work, I wanted an ability to use servor
without even npm installing my dependencies π π
One way I was thinking to solve this, is by adding a check in servor
to see if we are serving a JS file. If a JS file is not available locally, we rewrite the URL to UNPKG CDN URL.
For Example:
Let's say I have code like this in say index.js
:
import { patch, h } from 'superfine';
import store from '@vanillajs/store';
servor
would rewrite this to something like this (when node_modules
is not available):
import { patch, h } from 'https://unpkg.com/[email protected]?type=module';
import store from 'https://unpkg.com/@vanillajs/[email protected]?type=module';
To take it a step further, if I do not have package.json
, we simply rewrite the URL to something like this:
import { patch, h } from 'https://unpkg.com/superfine?type=module';
import store from 'https://unpkg.com/@vanillajs/store?type=module';
This idea has been explored before with owc-dev-server and works quite well using express-transform-bare-module-specifiers
However, I would like a no-dependency solution for this to be available in servor
thoughts/concerns?
Hi, please add LICENSE.txt. Otherwise according to copyright notice here, your project cannot be used.. :)
Currently, when I open something like localhost:8080/path
, I get the fallback /index.html
file instead of an existing file /path/index.html
. Most servers, including GitHub pages, are by default configured "smartly" and return the index.html file (if it exists) when a folder is requested. Would be nice for this to be configurable, or maybe even default?
Thanks for putting this together! Unfortunately it doesn't work for my use case:
I'm accessing my dev box from my iOS device over a LAN. When I enter my IP address into Safari, I see "This Connection Is Not Private". If I tap on "Show Details", then "visit this website", it just leads me back to the original screen showing "This Connection Is Not Private".
I have been using an extremely hacking workaround described here. It would be great if I could use servor instead!
There should be an option to listen on localhost (127.0.0.1) only, not on LAN.
I am using servor for SPA app development, and would like to proxy my /api requests to my node api backend. Does servor support proxying requests?
Hello!
I am using servor for a web application I am building and I was wondering if there is an option to set up the service-worker-allowed
for the site service worker.
Thanks in advance
In some cases, like running along side Cypress, I don't need Chrome to auto-open, since Cypress has it's own isolated browser. Would it be possible to have a --no-open
flag to prevent this feature. I think it's fine and usually preferable as a default to open, so I think the flag just needs to be for opt-out of this behaviour rather than opt-in.
When I add servor as a dev dependency and try run serve a local instance with the "--secure" flag (along with providing some server.key and server.crt files) I get an error at the line where you call
process.setuid(501);
stating:
UnhandledPromiseRejectionWarning: Error: EPERM, Operation not permitted
If I remove that call, it passes effortlessly. Maybe there's a reason to changing the process uid that I am not competent enough. Anyways - if it can be made explicit you are breaking some security laws, it should be allowed, I think. Moreover, the browser is warning me as well any time I hit my homepage.
Kudos,
Kosta
When using the --reload
option, the browser disobeys the specified doctype I have. This is apparently because placing any content before the doctype forces the browser into quirks mode.
Make sure you put the DOCTYPE right at the beginning of your HTML document. Anything before the DOCTYPE, like a comment or an XML declaration will trigger quirks mode in Internet Explorer 9 and older.
Well... this happens to break Safari, Firefox and Chrome for me in weird ways. It led me to write invalid/incomplete flexbox css which is broken in standards mode π . After doing a non-dev build, I found out a lot of my site was messed up.
This is what the browser is receiving:
These are the two problem lines that can cause this behaviour.
if (isRoute && inject) file = inject + file;
if (isRoute && reload) file = livereload + file;
Would doing file + livereload
work instead maybe?
I have noticed then when watching large files the browser might reload before the file write is complete and show an error. One possible solution could be to check if stat.mtime
is changing (doc). I think chokidar solves this in a similar way.
The problem is that fs.watch
fires an event as soon as the file is changed - not when it is finished changing (in case of a longer write).
If you want I can try and make a PR?
If I start servor at the root of my git repo a refresh is triggered whenever I run git status
, git add
, git commit
etc.
It's not a huge issue, but there's no way currently of specifying folders for the watch to ignore. It might be nice to include such an option, it might also make sense to ignore some common folders like .git
or node_modules
.
Hi Luke,
This might not at all be an issue relevant to servΓΈr, but rather my total noobesse wrt service-workers. Just now starting to toy with service workers and made a real simple one:
const CACHE_NAME = 'cache'
self.addEventListener('install', event => {
caches.open(CACHE_NAME).then(cache => cache.addAll(['/index.html', '/index.js']))
})
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request).then(function(response) {
return response || fetch(event.request).then((response = {}))
})
)
})
When my index.html contains code for registering this service worker, servor starts up fine. But if I either reload once manually, or if I make a change to a file (to trigger a reload via the eventsource), I start getting these errors plopping out in my console:
Access to fetch at 'http://localhost:5000/' from origin 'http://localhost:8080' has been blocked by CORS policy: Request header field cache-control is not allowed by Access-Control-Allow-Headers in preflight response.
service-worker.js:1
Uncaught (in promise) TypeError: Failed to fetch
:5000/:1
GET http://localhost:5000/ net::ERR_FAILED
Somehow it seems when the service worker is intercepting the event source, it gets angry about cors headers.
Again, I'm just too much of a beginner to know wether this is something to fix in servor or with my service worker. Do you know?
As a simplicity project, servor
is excellent and very easy to use.
But do you have plans to support baseUrl
?
Considering that many people will use webpack( options.output.publicPath
or others), I think this option is very useful to support SPA development/preview.
Then we can:
servor dist --baseUrl admin
ββ
http://localhost:8080/ --> Error 404 or Friendly Tips.
http://localhost:8080/admin/ --> ./dist/index.html
create-react-app
automatically serves to localhost and a local IP address so I can easily access the website from my phone. I have literally 0 idea on how this works or how difficult it is to do, but would love to see in servor!
error occurred and server is killed.
/usr/local/lib/node_modules/http-server-spa/server.js:76
const resource = path.join(cwd, root, decodeURI(uri));
^
URIError: URI malformed
at decodeURI (<anonymous>)
at Server.<anonymous> (/usr/local/lib/node_modules/http-server-spa/server.js:76:43)
at Server.emit (node:events:513:28)
at parserOnIncoming (node:_http_server:1091:12)
at HTTPParser.parserOnHeadersComplete (node:_http_common:119:17)
Spinoff of a convo here: FredKSchott/snowpack#145
I know that I'll commonly have to restart my dev server multiple times during development, just as I switch around different terminals and tasks and such. When the dev server switches ports on me, I have to go update any URLs in any open browser tabs, instead of just refreshing the page. There's something less confusing about it as well, to have less changing/moving parts.
Obviously you can configure the port, but the fact that I also need to know the two options that come before it makes that less simple. Putting those three options behind flags so that I could do something like servor -p 1234
/servor --port 1234
would be an improvement as well.
^ This is half personal opinion, and half me giving feedback based on writing the Snowpack docs and trying to keep things simple.
Hey, Luke ππ»
So I was trying snowpack out, and the docs brought me here. Their doc highly recommends servor
. π I've watched you in YT on pushing the web forward on a bundle-less future. I'm excited that it's becoming more mainstream.
So I'm using this in Ubuntu via WSL / Windows 10; while it reloads fine when I change the index.html, it doesn't reload if I change the JS file.
Here's a screencast I made to document the error.
In server.js line 94, listen method is listening only to localhost, its broken on services like Heroku.
Using the API, I start two instances of Servor without waiting the first promise to finish, without port specified, the net
library cause them to have the same port.
If I just do this it works:
const usePort = (port = 0) =>
new Promise((ok, x) => {
setTimeout(() => {
const s = net.createServer();
s.on('error', x);
s.listen(port, () => (a = s.address()) && s.close(() => ok(a.port)));
})
});
They have two differents ports, (51159 and 51160 for example).
Hello! I am trying to get this working with my react app to test on IE11 in windows and can't get it to work. Seems to work fine in other browsers. I have a little express server (super basic) that will serve and render my app in IE11 no problem.
Are there known incompatibilities with Windows and/or IE11?
I am trying to start with --secure option , i have the crt and key file placed in the directory where i am starting the servor but it is not picking up the file.
Question is where should i put these files in?
Currently many file types like 'js', 'css', 'html', 'json', 'xml', 'svg'
get automatically encoded as gzip and the Header content-encoding
will be set to gzip
. In my project I use esbuild with an compression plugin to automatically encode all bundles as brΓΆtli. Since servor doesn't check for gz
or br
file extension these files get served wrong.
gz
and br
and set the right content headers
{
"headers": [
{
"source": "dist/serviceWorker.js",
"headers": [{ "key": "Service-Worker-Allowed", "value": "/" }]
},
{
"source" : "dist/*.br",
"headers" : [{ "key" : "Content-Encoding", "value" : "br" }]
}
]
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.