Permalink
Browse files

fix: publicPath should contains leading and trailing slash (#9)

  • Loading branch information...
popomore committed Mar 29, 2018
1 parent 5db9e90 commit 3f0255680aa8f6460faf08957efdff184c781b3f
2 app.js
@@ -7,7 +7,7 @@ const AssetsView = require('./lib/assets_view');

module.exports = app => {
const assetsConfig = app.config.assets;
if (assetsConfig.isLocal && !assetsConfig.url) {
if (assetsConfig.isLocal && !assetsConfig.url && assetsConfig.devServer.port) {
assetsConfig.url = 'http://127.0.0.1:' + assetsConfig.devServer.port;
}

@@ -5,21 +5,28 @@ const utility = require('utility');

const CONTEXT_TEMPLATE_ID = 'context' + utility.sha1(String(Date.now()));

// URL consists of host, resourceBase and entry,
// E.X. http://127.0.0.1:7001/public/index.js
// host is http://127.0.0.1:7001
// resourceBase is /public/
// entry is index.js
class Assets {

constructor(ctx) {
this.ctx = ctx;
this.config = ctx.app.config.assets;
this.isLocal = this.config.isLocal;
this.manifest = this.config.manifest;
// publicPath should contain trailing / and leading /
this.publicPath = this.isLocal ? '/' : normalizePublicPath(this.config.publicPath);
}

get host() {
return this.config.url;
}

get resourceBase() {
if (this.isLocal) return this.host + '/';
return `${this.host}${this.config.publicPath}/`;
return `${this.host}${this.publicPath}`;
}

getStyle(entry) {
@@ -31,8 +38,8 @@ class Assets {
entry = entry || this.entry;

let script = '';
if (this.config.publicPath) {
script = `<script>window.__webpack_public_path__ = '${this.config.publicPath}';</script>`;
if (this.publicPath) {
script = `<script>window.__webpack_public_path__ = '${this.publicPath}';</script>`;
}
script += scriptTpl({ url: this.getURL(entry) });
return script;
@@ -45,6 +52,15 @@ class Assets {
return ret;
}

getURL(entry) {
let urlpath = entry;
if (!this.isLocal) {
urlpath = this.manifest[urlpath];
assert(urlpath, `Don't find ${entry} in manifest.json`);
}
return `${this.resourceBase}${urlpath}`;
}

setEntry(entry) {
this.entry = entry;
this.entryCss = entry.replace(/\.jsx?$/, '.css');
@@ -54,16 +70,6 @@ class Assets {
this.assetsContext = context;
}

getURL(entry) {
if (this.isLocal) {
return `${this.host}/${entry}`;
}

const urlpath = this.manifest[entry];
assert(urlpath, `Don't find ${entry} in manifest.json`);
return `${this.resourceBase}${urlpath}`;
}

}

module.exports = Assets;
@@ -87,3 +93,12 @@ function safeStringify(data) {
return escapeMap[ch];
});
}

function normalizePublicPath(publicPath) {
if (!publicPath) return '/';
let firstIndex = 0;
if (publicPath[firstIndex] === '/') firstIndex++;
let lastIndex = publicPath.length - 1;
if (publicPath[lastIndex] === '/') lastIndex--;
return '/' + publicPath.slice(firstIndex, lastIndex + 1) + '/';
}
@@ -3,6 +3,7 @@
const path = require('path');
const mock = require('egg-mock');
const fs = require('mz/fs');
const assert = require('assert');


describe('test/assets.test.js', () => {
@@ -18,7 +19,7 @@ describe('test/assets.test.js', () => {
app = mock.cluster({
baseDir: 'apps/assets',
});
app.debug();
// app.debug();
return app.ready();
});
after(() => app.close());
@@ -30,7 +31,7 @@ describe('test/assets.test.js', () => {
.expect(/<link rel="stylesheet" href="http:\/\/127.0.0.1:8000\/index.css"><\/link>/)
.expect(/style="display:none">{"data":1}<\/div>/)
.expect(/<script src="http:\/\/127.0.0.1:8000\/index.js"><\/script>/)
.expect(/<script>window.__webpack_public_path__ = '\/app\/public';<\/script>/)
.expect(/<script>window.__webpack_public_path__ = '\/';<\/script>/)
.expect(200);
});
});
@@ -54,7 +55,7 @@ describe('test/assets.test.js', () => {
.expect(/<link rel="stylesheet" href="http:\/\/cdn.com\/app\/public\/index.b8e2efea.css"><\/link>/)
.expect(/style="display:none">{"data":1}<\/div>/)
.expect(/<script src="http:\/\/cdn.com\/app\/public\/index.c4ae6394.js"><\/script>/)
.expect(/<script>window.__webpack_public_path__ = '\/app\/public';<\/script>/)
.expect(/<script>window.__webpack_public_path__ = '\/app\/public\/';<\/script>/)
.expect(200);
});
});
@@ -166,7 +167,7 @@ describe('test/assets.test.js', () => {
.expect(/<link rel="stylesheet" href="http:\/\/127.0.0.1:8000\/index.css"><\/link>/)
.expect(/style="display:none">{"data":1}<\/div>/)
.expect(/<script src="http:\/\/127.0.0.1:8000\/index.js"><\/script>/)
.expect(/<script>window.__webpack_public_path__ = '\/app\/public';<\/script>/)
.expect(/<script>window.__webpack_public_path__ = '\/';<\/script>/)
.expect(/<script>window.resourceBaseUrl = 'http:\/\/127.0.0.1:8000\/';<\/script/)
.expect(200);
});
@@ -188,7 +189,7 @@ describe('test/assets.test.js', () => {
.expect(/<link rel="stylesheet" href="http:\/\/cdn.com\/app\/public\/index.b8e2efea.css"><\/link>/)
.expect(/style="display:none">{"data":1}<\/div>/)
.expect(/<script src="http:\/\/cdn.com\/app\/public\/index.c4ae6394.js"><\/script>/)
.expect(/<script>window.__webpack_public_path__ = '\/app\/public';<\/script>/)
.expect(/<script>window.__webpack_public_path__ = '\/app\/public\/';<\/script>/)
.expect(/<script>window.resourceBaseUrl = 'http:\/\/cdn.com\/app\/public\/';<\/script/)
.expect(200);
});
@@ -254,4 +255,106 @@ describe('test/assets.test.js', () => {
.expect(200);
});
});

describe('publicPath', () => {
let app;

describe('local', () => {
before(() => {
mock.env('local');
app = mock.app({
baseDir: 'apps/custom-public-path',
});
return app.ready();
});
after(() => app.close());

it('should render with trailing /', () => {
mock(app.config.assets, 'publicPath', '/public/');

let ctx = app.mockContext();
ctx.helper.assets.setEntry('index.js');
let script = ctx.helper.assets.getScript();
assert(script.includes('__webpack_public_path__ = \'/\';'));
assert(script.includes('src="/index.js"'));
let style = ctx.helper.assets.getStyle();
assert(style.includes('href="/index.css"'));

ctx = app.mockContext();
script = ctx.helper.assets.getScript('index.js');
assert(script.includes('__webpack_public_path__ = \'/\';'));
assert(script.includes('src="/index.js"'));
style = ctx.helper.assets.getStyle('index.css');
assert(style.includes('href="/index.css"'));
});

it('should render without trailing /', () => {
mock(app.config.assets, 'publicPath', '/public');

let ctx = app.mockContext();
ctx.helper.assets.setEntry('index.js');
let script = ctx.helper.assets.getScript();
assert(script.includes('__webpack_public_path__ = \'/\';'));
assert(script.includes('src="/index.js"'));
let style = ctx.helper.assets.getStyle();
assert(style.includes('href="/index.css"'));

ctx = app.mockContext();
script = ctx.helper.assets.getScript('index.js');
assert(script.includes('__webpack_public_path__ = \'/\';'));
assert(script.includes('src="/index.js"'));
style = ctx.helper.assets.getStyle('index.css');
assert(style.includes('href="/index.css"'));
});
});

describe('prod', () => {
before(() => {
mock.env('prod');
app = mock.app({
baseDir: 'apps/custom-public-path',
});
return app.ready();
});
after(() => app.close());

it('should render with trailing /', () => {
mock(app.config.assets, 'publicPath', '/public/');

let ctx = app.mockContext();
ctx.helper.assets.setEntry('index.js');
let script = ctx.helper.assets.getScript();
assert(script.includes('__webpack_public_path__ = \'/public/\';'));
assert(script.includes('src="/public/index.js"'));
let style = ctx.helper.assets.getStyle();
assert(style.includes('href="/public/index.css"'));

ctx = app.mockContext();
script = ctx.helper.assets.getScript('index.js');
assert(script.includes('__webpack_public_path__ = \'/public/\';'));
assert(script.includes('src="/public/index.js"'));
style = ctx.helper.assets.getStyle('index.css');
assert(style.includes('href="/public/index.css"'));
});

it('should render without trailing /', () => {
mock(app.config.assets, 'publicPath', '/public');

let ctx = app.mockContext();
ctx.helper.assets.setEntry('index.js');
let script = ctx.helper.assets.getScript();
assert(script.includes('__webpack_public_path__ = \'/public/\';'));
assert(script.includes('src="/public/index.js"'));
let style = ctx.helper.assets.getStyle();
assert(style.includes('href="/public/index.css"'));

ctx = app.mockContext();
script = ctx.helper.assets.getScript('index.js');
assert(script.includes('__webpack_public_path__ = \'/public/\';'));
assert(script.includes('src="/public/index.js"'));
style = ctx.helper.assets.getStyle('index.css');
assert(style.includes('href="/public/index.css"'));
});
});
});
});
@@ -0,0 +1,11 @@
'use strict';

const Controller = require('egg').Controller;

class HomeController extends Controller {
async index() {
await this.ctx.render('index.js');
}
}

module.exports = HomeController;
@@ -0,0 +1,7 @@
'use strict';

module.exports = app => {
const { router, controller } = app;

router.get('/', controller.home.index);
};
@@ -0,0 +1,10 @@
'use strict';

exports.keys = '123456';
exports.view = {
mapping: {
'.js': 'assets',
},
};
exports.assets = {
};
@@ -0,0 +1,4 @@
{
"index.js": "index.js",
"index.css": "index.css"
}
@@ -0,0 +1,10 @@
#!/usr/bin/env node

'use strict';

console.log('[server] cwd:', process.cwd());
console.log('[server] DEBUG:', process.env.DEBUG);

if (process.env.EXIT) {
process.exit(1);
}
@@ -0,0 +1,3 @@
{
"name": "egg-view-assets"
}

0 comments on commit 3f02556

Please sign in to comment.