Coder Social home page Coder Social logo

lukejacksonn / servor Goto Github PK

View Code? Open in Web Editor NEW
1.0K 9.0 68.0 123 KB

Dependency free file server for single page app development

License: MIT License

JavaScript 90.27% CSS 1.94% HTML 1.57% Shell 2.50% AppleScript 3.72%
development server single-page-app live-reload file-watcher history-api-fallback

servor's Issues

Trailing slash on SPA route

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/

`sudo servor --secure` throws `EACCES: permission denied`

I'm trying to install the certs so that I won't see the "⚠️ Your connection is not private" screen.

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

Media streaming issues with Chrome

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.

Add flow support

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
  }
});

Specify port without fallback?

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.

Nested routes

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

[Feature Request] Allow multiple roots

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.

[Feature Request] Inject livereload to each html file

Each served html should have livereloading functional. For now it works only for index.html files.

Why

To use servor livereload feature not only for spa, but for traditional sites as well.

How

I believe this should work as default, but it could be opt-in.

Workaround

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

Vertical scroll position resets when servor triggers reloading in Firefox

This is probably firefox issue (or even just me). But maybe is it related to servor configuration?

  1. Serve some page with servor --reload, open it in FF
  2. Scroll the page vertically
  3. Trigger a reload with style changing
  4. Page reloads but the scroll position is reset

Additional 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.

Option for disable the injection of base tag

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?

unpkg CDN as a fallback?

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?

index.html as default file in subfolders?

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?

Support https for LAN IP

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!

Proxy support

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?

Service Workers

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

Opt-out of automatically opening url

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.

setuid breaks local secure serving on linux

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

--reload causes browsers to enter quirks mode

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:
before doctype

These are the two problem lines that can cause this behaviour.

if (isRoute && inject) file = inject + file;
if (isRoute && reload) file = livereload + file;

Possible solution

Would doing file + livereload work instead maybe?

Wait for write to finish

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?

ignore folders and/or ignore .git folder by default

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.

cors issues with localhost:5000 and service worker

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?

BaseUrl support?

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

Serve to local IP address?

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!

Exception handling in the `decodeURI` function is required.

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)

Port behavior/configuration

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.

Doesn't detect change in nested files (on Linux)

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.

Starting two instances of Servor without port cause them having the same port

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).

IE11 Compatibility? Windows Compatibility?

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?

image

crt and key file location for secure start

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?

Support already encoded files (gz, br)

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.

  • Proposol 1: Check for file extensions gz and br and set the right content headers
    • Advantages: Very simple
    • Disadvantages: Not very flexibel
  • Proposal 2: Give the user the possibilitry to add configuration file which adds
    • Advantages:
      • Gives the power back to the user of the package to freely add headers depending on his needs
      • Also handles other use cases like shown in the example above
    • Disadvantages:
      • More Complex
    • Example: With other servers I could for example add an file like:
{
  "headers": [
    {
      "source": "dist/serviceWorker.js",
      "headers": [{ "key": "Service-Worker-Allowed", "value": "/" }]
    },
    {
      "source" : "dist/*.br",
      "headers" : [{ "key" : "Content-Encoding", "value" : "br" }]
    }
  ]
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.