-
-
Notifications
You must be signed in to change notification settings - Fork 380
feat(middleware): add content
option (options.content.filter
, options.content.transform
)
#336
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Added explicit "NotFound" flag, will be used in the subsequent features
lib/middleware.js
Outdated
if (!context.options.content.filter(currentRequest)) { | ||
return goNext(); | ||
} | ||
} | ||
if (notFound) { | ||
return resolve(goNext()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: why is it that every other "goNext" is a regular return but this one is a return resolve(goNext())?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question but I don't know the answer, try to remove the resolve
and see what's happening (if something happens). Please add a comment that this is something to investigate and clearify :)
if (notFound) { | ||
return localResolve(null); | ||
} | ||
fs.readFile(localRequest.filename, (err, content) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it a problem that the readFileSync was replaced by an async one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't say to 💯, but async I/O should be preferred. Maybe add a comment that it was changed in case we need to (temp) revert this for some reason :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fs
is a in memory filesystem so it doesn't matter
Missing: changing the README.md, working on it but it would gain some time to request comments on the code itself meanwhile. |
// do not add charset to WebAssembly files, otherwise compileStreaming will fail in the client | ||
if (!/\.wasm$/.test(filename)) { | ||
contentType += '; charset=UTF-8'; | ||
const currentRequest = Object.assign({}, { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const currentRequest
=> const request
(we don't have different/multiple request(s) in this context)
if (notFound) { | ||
return localResolve(null); | ||
} | ||
fs.readFile(localRequest.filename, (err, content) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't say to 💯, but async I/O should be preferred. Maybe add a comment that it was changed in case we need to (temp) revert this for some reason :)
} | ||
const defaultTransform = (localRequest, fs) => new Promise((localResolve) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why localRequest && localResolve
instead of just req(uest) && resolve
? If it is because of the linter feel free to add a e.g /* eslint-disable no-shadow */
to the top of the file :)
} | ||
}); | ||
}); | ||
const optionTransform = (context.options && context.options.content) ? context.options.content.transform : null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmmm I not sure 💯 here, but something in the direction of
const { options, fs } = context
// readFile -> Object { request, content, fs }
const readFile = (request, fs) => new Promise((resolve) => {
...
return { request, content, fs }
})
// transform -> Promise<String|?Buffer>
const transform = (options.content && options.content.transform)
? options.content.transform
: ({ request, content, fs }) => content // default
return readFile(request, fs)
.then(transform)
.then((content) => { ... })
maybe, but definitely open for suggestions
instance = middleware(compiler, { | ||
stats: 'errors-only', | ||
content: { | ||
filter(currentRequest) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
currentRequest
=> res || request
@@ -38,6 +38,7 @@ module.exports = function wrapper(context) { | |||
return new Promise(((resolve) => { | |||
handleRequest(context, filename, processRequest, req); | |||
function processRequest() { | |||
let notFound; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please elaborate further on the need for this
res.setHeader(name, context.options.headers[name]); | ||
const { headers } = context.options; | ||
if (headers) { | ||
for (const name in headers) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
name
=> header
.then(content => ((!optionTransform) ? content : optionTransform(currentRequest, content, context.fs))) | ||
.then((content) => { | ||
if (content == null) { | ||
return Promise.reject(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we better reject with an {Error}
here ?
if (content == null) {
const err = new Error('<message>')
return Promise.reject(err)
}
Yep, let's discuss the implementation first and once approved you can add the docs then :) |
This overall looks very good :) How in your opinion could this potentially replace |
Codecov Report
@@ Coverage Diff @@
## master #336 +/- ##
==========================================
- Coverage 96.82% 96.64% -0.19%
==========================================
Files 7 7
Lines 252 268 +16
==========================================
+ Hits 244 259 +15
- Misses 8 9 +1
Continue to review full report at Codecov.
|
@michael-ciniawsky can we describe this feature in main post briefly, it is hard to read a lot of posts? |
Here is the shortest summary:
The added tests contain examples of use cases for these options and, in general, they supercede what's being offered by |
@ferdinando-ferreira do you need server side rendering for development env? Also please provide you stack for ssr (frameworks, react/vue/etc, simple example, better repo) |
It is my belief that the test environment should be as close if not an exact replica of the production one including all features. That makes testing the rendering of the project with SSR important as it can showcase eventual inconsistencies to be fixed during development.
Here is an example I prepared to showcase the full power of the proposed solution. It is a fully featured turnkey hot reloaded server side rendered single file component powered environment to develop vuejs applications.
As of now (as it can be seen at #306) the way to properly implement SSR consists in essentially to tell webpack-dev-middleware not to serve a certain file (in a roundabout way, by passing a "falsy" value on the index field) and, then, to serve it in a subsequent middleware. git clone --single-branch -b samples https://github.com/ferdinando-ferreira/webpack-dev-middleware.git
cd webpack-dev-middleware
npm install
cd samples
cd vue-ssr
npm install
npm run dev Here is the commit with the sample code referenced above. |
What do you think about this solution? |
@evilebottnawi: There are two components in the suggestion
That is not accurate for the use case proposed for this PR. Any transformation done through plugins or loaders only happen in compile time, making it necessary to restart the server and recompile for it any change to it to have effect. Here is an example: in the code mentioned at #336 (comment), while running its development server through
Without the middleware level transform (doing it with a plugin, for instance) would make necessary to stop the dev server, start the dev server for the route change to take effect. Here is an example. Edit the following file samples/vue-ssr/src/components/App.vue: Change <ul class="links">
<router-link :to="{ name: 'home' }" tag="li"><a>Home</a></router-link>
<router-link :to="{ name: 'about' }" tag="li"><a>About</a></router-link>
<router-link to="/nopage" tag="li"><a>Missing page</a></router-link>
<router-link to="/nopage2" tag="li"><a>Missing page 2</a></router-link>
</ul> with <ul class="links">
<router-link :to="{ name: 'home' }" tag="li"><a>Home</a></router-link>
<router-link :to="{ name: 'about' }" tag="li"><a>About</a></router-link>
<router-link to="/nopage" tag="li"><a>Missing page</a></router-link>
<router-link to="/nopage2" tag="li"><a>Missing page 2</a></router-link>
<router-link :to="{ name: 'home2' }" tag="li"><a>Home 2</a></router-link>
</ul> and export const routes = [
{ name: 'home', path: '/', component: Home, meta: { title: 'Homepage' } },
{ name: 'about', path: '/about', component: About, meta: { title: 'About' } },
{ name: 'notfound', path: "*", component: NotFound, meta: { title: 'Not Found' } }
]; with export const routes = [
{ name: 'home', path: '/', component: Home, meta: { title: 'Homepage' } },
{ name: 'about', path: '/about', component: About, meta: { title: 'About' } },
{ name: 'notfound', path: "*", component: NotFound, meta: { title: 'Not Found' } },
{ name: 'home2', path: '/home2', component: Home, meta: { title: 'Homepage 2' } }
]; Refresh the page (HMR is not working properly, product of a soon to be filed bug with To the best of my knowledge there is no way to replicate this behaviour with the use of plugins because they're invoked in compile time while the middleware is invoked in page load time.
The largest obstacle here (the one this new option is trying to solve) is the fact Please confirm if this option has a chance of getting approved so I can work on the changes requested by @michael-ciniawsky or table the request. Best regards |
Done, PR #337. Both PRs solve the same issue, this one in a more generic fashion, the other one contingent on ServerSideRender flag not going away. |
Rescinding this PR, #337 is enough as long as ServerSideRequest doesn't get dropped. |
We will definitely keep it until we found a equally sufficient replacement for SSR workflows. I will review #337 asap. Thx for your efforts on this so far :) |
What kind of change does this PR introduce?
Feature
Did you add tests for your changes?
Yes
Summary
It's a refactoring of the functionality proposed at #330 with the requested changes implemented