From 047cbf9d59822beb34fb6c2be5f043eb049dcc55 Mon Sep 17 00:00:00 2001 From: Jean Regisser Date: Mon, 19 Sep 2016 10:32:42 -0700 Subject: [PATCH] Fix iOS unchanged local assets refetched from packager in development Summary: Hi, This PR fixes the problem described by chrisnojima in https://github.com/facebook/react-native/issues/9581#issuecomment-243766310 **Test plan** In development mode, - Run an app with an image: `` - Notice that you see the following in packager console: ```txt 6:46:42 PM] processing asset request logo.png [6:46:42 PM] processing asset request logo.png (1ms) ``` - Reload the app, or navigate to another page of the app with the same image - Notice that you see again: ```txt 6:47:23 PM] processing asset request logo.png [6:47:23 PM] processing asset request logo.png (1ms) ``` Now wih the fix applied, notice that you only see `logo.png` fetched once, even if you reload or show the same image in a different part of the app. Let me know what you think. Closes https://github.com/facebook/react-native/pull/9795 Differential Revision: D3876945 Pulled By: davidaurelio fbshipit-source-id: f41f4719e87644692a690123fd6e54eead9cc87d --- react-packager/src/Server/__tests__/Server-test.js | 12 ++++++++---- react-packager/src/Server/index.js | 7 ++++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/react-packager/src/Server/__tests__/Server-test.js b/react-packager/src/Server/__tests__/Server-test.js index de497d44..c5037909 100644 --- a/react-packager/src/Server/__tests__/Server-test.js +++ b/react-packager/src/Server/__tests__/Server-test.js @@ -337,30 +337,32 @@ describe('processRequest', () => { describe('/assets endpoint', () => { it('should serve simple case', () => { const req = {url: '/assets/imgs/a.png'}; - const res = {end: jest.fn()}; + const res = {end: jest.fn(), setHeader: jest.fn()}; AssetServer.prototype.get.mockImpl(() => Promise.resolve('i am image')); server.processRequest(req, res); jest.runAllTimers(); + expect(res.setHeader).toBeCalledWith('Cache-Control', 'max-age=31536000'); expect(res.end).toBeCalledWith('i am image'); }); it('should parse the platform option', () => { const req = {url: '/assets/imgs/a.png?platform=ios'}; - const res = {end: jest.fn()}; + const res = {end: jest.fn(), setHeader: jest.fn()}; AssetServer.prototype.get.mockImpl(() => Promise.resolve('i am image')); server.processRequest(req, res); jest.runAllTimers(); expect(AssetServer.prototype.get).toBeCalledWith('imgs/a.png', 'ios'); + expect(res.setHeader).toBeCalledWith('Cache-Control', 'max-age=31536000'); expect(res.end).toBeCalledWith('i am image'); }); it('should serve range request', () => { const req = {url: '/assets/imgs/a.png?platform=ios', headers: {range: 'bytes=0-3'}}; - const res = {end: jest.fn(), writeHead: jest.fn()}; + const res = {end: jest.fn(), writeHead: jest.fn(), setHeader: jest.fn()}; const mockData = 'i am image'; AssetServer.prototype.get.mockImpl(() => Promise.resolve(mockData)); @@ -368,18 +370,20 @@ describe('processRequest', () => { server.processRequest(req, res); jest.runAllTimers(); expect(AssetServer.prototype.get).toBeCalledWith('imgs/a.png', 'ios'); + expect(res.setHeader).toBeCalledWith('Cache-Control', 'max-age=31536000'); expect(res.end).toBeCalledWith(mockData.slice(0, 4)); }); it('should serve assets files\'s name contain non-latin letter', () => { const req = {url: '/assets/imgs/%E4%B8%BB%E9%A1%B5/logo.png'}; - const res = {end: jest.fn()}; + const res = {end: jest.fn(), setHeader: jest.fn()}; AssetServer.prototype.get.mockImpl(() => Promise.resolve('i am image')); server.processRequest(req, res); jest.runAllTimers(); expect(AssetServer.prototype.get).toBeCalledWith('imgs/主页/logo.png', undefined); + expect(res.setHeader).toBeCalledWith('Cache-Control', 'max-age=31536000'); expect(res.end).toBeCalledWith('i am image'); }); }); diff --git a/react-packager/src/Server/index.js b/react-packager/src/Server/index.js index 08576bbb..29efa796 100644 --- a/react-packager/src/Server/index.js +++ b/react-packager/src/Server/index.js @@ -493,7 +493,12 @@ class Server { const assetEvent = Activity.startEvent('Processing asset request', {asset: assetPath[1]}); this._assetServer.get(assetPath[1], urlObj.query.platform) .then( - data => res.end(this._rangeRequestMiddleware(req, res, data, assetPath)), + data => { + // Tell clients to cache this for 1 year. + // This is safe as the asset url contains a hash of the asset. + res.setHeader('Cache-Control', 'max-age=31536000'); + res.end(this._rangeRequestMiddleware(req, res, data, assetPath)); + }, error => { console.error(error.stack); res.writeHead('404');