hauler 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.babelrc +1 -0
- data/.eslintrc +5 -1
- data/.gitignore +1 -0
- data/.nvmrc +1 -0
- data/Makefile +6 -1
- data/bin/dev-server.js +6 -4
- data/bin/read-config.js +15 -0
- data/bin/update-scripts.js +1 -1
- data/lib/generators/hauler/install_generator.rb +5 -1
- data/lib/generators/hauler/install_npm_generator.rb +1 -0
- data/lib/generators/hauler/templates/config/hauler.js +9 -5
- data/lib/generators/hauler/templates/config/initializers/hauler.rb +1 -0
- data/lib/generators/hauler/templates/eslintrc.json +1 -3
- data/lib/generators/hauler/templates/webpack.config.js +4 -3
- data/lib/hauler/helpers/hauler_helper.rb +76 -0
- data/lib/hauler/railtie.rb +11 -18
- data/lib/hauler/version.rb +6 -1
- data/lib/hauler.rb +3 -0
- data/make-package.js +11 -1
- data/package.json +24 -9
- data/src/decls/hauler.js +7 -0
- data/src/decls/webpack.js +16 -11
- data/src/defaults/compiler_config_factory.js +5 -96
- data/src/defaults/dev_server_config_factory.js +3 -4
- data/src/defaults/project_config_factory.js +109 -0
- data/src/index.js +25 -104
- data/src/utils/__tests__/extract_config-test.js +132 -0
- data/src/utils/__tests__/merge_config-test.js +75 -0
- data/src/utils/__tests__/path-test.js +26 -0
- data/src/utils/extract_config.js +103 -0
- data/src/utils/index.js +6 -0
- data/src/utils/merge_config.js +34 -0
- data/src/utils/misc.js +61 -0
- data/src/utils/path.js +73 -0
- data/wallaby.js +20 -0
- metadata +16 -4
- data/lib/hauler/asset_tag_helper.rb +0 -27
- data/src/utils.js +0 -103
@@ -0,0 +1,109 @@
|
|
1
|
+
// @flow
|
2
|
+
|
3
|
+
import ExtractTextPlugin from 'extract-text-webpack-plugin';
|
4
|
+
import * as webpack from 'webpack';
|
5
|
+
|
6
|
+
import devServerConfigFactory from './dev_server_config_factory';
|
7
|
+
import compilerConfigFactory from './compiler_config_factory';
|
8
|
+
|
9
|
+
function getPlugins(env: string) {
|
10
|
+
let plugins = [
|
11
|
+
new webpack.ProvidePlugin({ fetch: 'exports?self.fetch!whatwg-fetch' }),
|
12
|
+
new webpack.DefinePlugin({ 'process.env': { NODE_ENV: JSON.stringify(env) } }),
|
13
|
+
new webpack.optimize.CommonsChunkPlugin({
|
14
|
+
name: 'vendor',
|
15
|
+
children: true,
|
16
|
+
minChunks: 2,
|
17
|
+
async: true,
|
18
|
+
}),
|
19
|
+
];
|
20
|
+
|
21
|
+
if (env === 'development') {
|
22
|
+
plugins = plugins.concat([
|
23
|
+
new webpack.NoErrorsPlugin(),
|
24
|
+
]);
|
25
|
+
}
|
26
|
+
|
27
|
+
if (env === 'production') {
|
28
|
+
plugins = plugins.concat([
|
29
|
+
new webpack.optimize.OccurrenceOrderPlugin(true),
|
30
|
+
new webpack.optimize.DedupePlugin(),
|
31
|
+
new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }),
|
32
|
+
new ExtractTextPlugin('[name].[contenthash].css'),
|
33
|
+
]);
|
34
|
+
}
|
35
|
+
|
36
|
+
return plugins;
|
37
|
+
}
|
38
|
+
|
39
|
+
function configFactory(env: string) {
|
40
|
+
const entries = {};
|
41
|
+
|
42
|
+
// individual loaders so that they can be replaced separately
|
43
|
+
const javascriptLoader = {
|
44
|
+
test: /\.jsx?$/,
|
45
|
+
loader: 'babel',
|
46
|
+
exclude: /node_modules/,
|
47
|
+
query: {
|
48
|
+
presets: ['es2015', 'react', 'stage-2'],
|
49
|
+
plugins: ['transform-class-properties'],
|
50
|
+
},
|
51
|
+
};
|
52
|
+
|
53
|
+
const sassLoader = {
|
54
|
+
test: /\.scss$/,
|
55
|
+
loader: 'style!css!sass',
|
56
|
+
};
|
57
|
+
|
58
|
+
const fontLoader = {
|
59
|
+
test: /\.(eot|svg|ttf|woff|woff2)$/,
|
60
|
+
loader: 'file',
|
61
|
+
};
|
62
|
+
|
63
|
+
const imageLoader = {
|
64
|
+
test: /\.(jpg|png|gif)$/,
|
65
|
+
loaders: [
|
66
|
+
'file',
|
67
|
+
'image-webpack?{progressive:true, optimizationLevel: 7, interlaced: false, pngquant:{quality: "65-90", speed: 4}}',
|
68
|
+
],
|
69
|
+
};
|
70
|
+
|
71
|
+
if (env === 'production') {
|
72
|
+
javascriptLoader.query.plugins = javascriptLoader.query.plugins.concat([
|
73
|
+
'transform-react-remove-prop-types',
|
74
|
+
'transform-react-constant-elements',
|
75
|
+
'transform-react-inline-elements',
|
76
|
+
]);
|
77
|
+
|
78
|
+
sassLoader.loader = ExtractTextPlugin.extract(
|
79
|
+
'style',
|
80
|
+
sassLoader.loader.replace('style!', '')
|
81
|
+
);
|
82
|
+
}
|
83
|
+
|
84
|
+
const appendPlugins = [];
|
85
|
+
const plugins = getPlugins(env);
|
86
|
+
const prependPlugins = [];
|
87
|
+
|
88
|
+
const publicPath = '/assets';
|
89
|
+
|
90
|
+
const devServer = devServerConfigFactory(env);
|
91
|
+
|
92
|
+
const compiler = compilerConfigFactory(env);
|
93
|
+
|
94
|
+
return {
|
95
|
+
entries,
|
96
|
+
javascriptLoader,
|
97
|
+
sassLoader,
|
98
|
+
fontLoader,
|
99
|
+
imageLoader,
|
100
|
+
prependPlugins,
|
101
|
+
plugins,
|
102
|
+
appendPlugins,
|
103
|
+
publicPath,
|
104
|
+
devServer,
|
105
|
+
compiler,
|
106
|
+
};
|
107
|
+
}
|
108
|
+
|
109
|
+
export default configFactory;
|
data/src/index.js
CHANGED
@@ -1,122 +1,43 @@
|
|
1
1
|
// @flow
|
2
|
-
// NOTE: This code is executed in a Gem, which makes any npm package unavailable
|
3
2
|
|
4
|
-
|
5
|
-
const devServerDefaultsFactory = require('./defaults/dev_server_config_factory');
|
6
|
-
const utils = require('./utils');
|
3
|
+
import * as utils from './utils';
|
7
4
|
|
8
|
-
function
|
9
|
-
|
10
|
-
|
11
|
-
config.sassLoader,
|
12
|
-
config.fontLoader,
|
13
|
-
config.imageLoader,
|
14
|
-
]);
|
5
|
+
function getProjectConfig(env: string): ProjectConfig {
|
6
|
+
const projectConfigFactory = require(utils.railsPath('~config/hauler.js'));
|
7
|
+
return projectConfigFactory(env);
|
15
8
|
}
|
16
9
|
|
17
|
-
function
|
18
|
-
const
|
19
|
-
|
20
|
-
return utils.deepMerge(resolve, { modules: utils.railsPath(modules) });
|
10
|
+
function getProjectDefaults(env: string): ProjectConfig {
|
11
|
+
const projectDefaultsFactory = require('./defaults/project_config_factory');
|
12
|
+
return projectDefaultsFactory.default(env);
|
21
13
|
}
|
22
14
|
|
23
|
-
function
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
function extractModule(config: ProjectConfig): WebpackModuleConfig {
|
31
|
-
const module = config.compiler && config.compiler.module;
|
32
|
-
return utils.deepMerge(module, {
|
33
|
-
loaders: extractLoaders(config),
|
34
|
-
});
|
35
|
-
}
|
36
|
-
|
37
|
-
function extractOutput(config: ProjectConfig): WebpackOutputConfig {
|
38
|
-
const output = config.compiler && config.compiler.output || {};
|
39
|
-
const path = output.path || '';
|
40
|
-
return utils.deepMerge(output, {
|
41
|
-
path: utils.railsPath(path),
|
42
|
-
});
|
43
|
-
}
|
44
|
-
|
45
|
-
function parseToCompilerConfig(config: ProjectConfig): WebpackConfig {
|
46
|
-
return {
|
47
|
-
entry: utils.railsPath(config.entries),
|
48
|
-
output: extractOutput(config),
|
49
|
-
module: extractModule(config),
|
50
|
-
plugins: extractPlugins(config),
|
51
|
-
resolve: extractResolve(config),
|
15
|
+
function getConfigFactory(): ProjectConfigFactory {
|
16
|
+
return (env: string) => {
|
17
|
+
const projectDefaults = getProjectDefaults(env);
|
18
|
+
const projectConfig = getProjectConfig(env);
|
19
|
+
const config = utils.mergeProjectConfig(projectDefaults, projectConfig);
|
20
|
+
return config;
|
52
21
|
};
|
53
22
|
}
|
54
23
|
|
55
|
-
function
|
56
|
-
|
57
|
-
|
58
|
-
return '';
|
24
|
+
export function getConfig(env: string, railsRoot?: string) {
|
25
|
+
if (railsRoot != null) {
|
26
|
+
utils.setRailsRoot(railsRoot);
|
59
27
|
}
|
60
28
|
|
61
|
-
|
62
|
-
|
63
|
-
}
|
64
|
-
|
65
|
-
const host = config.host || 'localhost';
|
66
|
-
const port = config.port || 30001;
|
67
|
-
return `http://${host}:${port}/${publicPath.replace(/^\//, '')}`;
|
68
|
-
}
|
69
|
-
|
70
|
-
function prepareDevServerConfig(config: WebpackDevServerConfig): WebpackDevServerConfig {
|
71
|
-
const output = Object.assign({}, config, {
|
72
|
-
publicPath: extractPublicPath(config),
|
73
|
-
});
|
74
|
-
|
75
|
-
return output;
|
29
|
+
const configFactory = getConfigFactory();
|
30
|
+
return configFactory(env);
|
76
31
|
}
|
77
32
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
* Returns a factory for getting the project webpack dev server configuration using the
|
82
|
-
* value of the `devServer` property in the result of `{Rails.root}/config/hauler.js`
|
83
|
-
*/
|
84
|
-
function webpackDevServerConfigFactory(defaultsFactory: DevServerConfigFactory) {
|
85
|
-
return (env: string): WebpackDevServerConfig => {
|
86
|
-
const defaultDevServerConfig = defaultsFactory(env);
|
87
|
-
const projectDevServerConfig = projectConfig.devServer;
|
88
|
-
const devServerConfig = utils.deepMerge(defaultDevServerConfig, projectDevServerConfig);
|
89
|
-
return prepareDevServerConfig(devServerConfig);
|
90
|
-
};
|
33
|
+
export function getDevServerConfig(env: string, railsRoot?: string): WebpackDevServerConfig {
|
34
|
+
const config = getConfig(env, railsRoot);
|
35
|
+
return utils.extractDevServerConfig(config);
|
91
36
|
}
|
92
37
|
|
93
|
-
function
|
94
|
-
|
95
|
-
|
96
|
-
const haulerProjectConfig = utils.deepMerge(defaultProjectConfig, projectConfig);
|
97
|
-
const webpackConfig = parseToCompilerConfig(haulerProjectConfig);
|
98
|
-
return utils.deepMerge(webpackConfig, projectConfig.compiler || {});
|
99
|
-
};
|
38
|
+
export function getCompilerConfig(env: string, railsRoot?: string): WebpackConfig {
|
39
|
+
const config = getConfig(env, railsRoot);
|
40
|
+
return utils.extractCompilerConfig(config);
|
100
41
|
}
|
101
42
|
|
102
|
-
|
103
|
-
getCompilerConfigFactory() {
|
104
|
-
return webpackCompilerConfigFactory(compilerDefaultsFactory);
|
105
|
-
},
|
106
|
-
|
107
|
-
getCompilerConfig(env: string) {
|
108
|
-
const configFactory = Hauler.getCompilerConfigFactory();
|
109
|
-
return configFactory(env);
|
110
|
-
},
|
111
|
-
|
112
|
-
getDevServerConfig(env: string) {
|
113
|
-
const configFactory = Hauler.getDevServerConfigFactory();
|
114
|
-
return configFactory(env);
|
115
|
-
},
|
116
|
-
|
117
|
-
getDevServerConfigFactory() {
|
118
|
-
return webpackDevServerConfigFactory(devServerDefaultsFactory);
|
119
|
-
},
|
120
|
-
};
|
121
|
-
|
122
|
-
module.exports = Hauler;
|
43
|
+
export { getEnvName } from './utils';
|
@@ -0,0 +1,132 @@
|
|
1
|
+
jest.disableAutomock();
|
2
|
+
|
3
|
+
const utils = require('../extract_config');
|
4
|
+
const pathUtils = require('../path');
|
5
|
+
|
6
|
+
describe('extractDevServerConfig', () => {
|
7
|
+
let projectConfigFactory;
|
8
|
+
let projectConfig;
|
9
|
+
|
10
|
+
beforeEach(() => {
|
11
|
+
projectConfigFactory = require('../../defaults/project_config_factory').default;
|
12
|
+
projectConfig = projectConfigFactory('development');
|
13
|
+
});
|
14
|
+
|
15
|
+
describe('contentBase', () => {
|
16
|
+
it('resolves to railsRoot', () => {
|
17
|
+
pathUtils.setRailsRoot('/var/www/hauler');
|
18
|
+
projectConfig.devServer.contentBase = '~lib/assets';
|
19
|
+
const config = utils.extractDevServerConfig(projectConfig);
|
20
|
+
expect(config.contentBase).toBe('/var/www/hauler/lib/assets');
|
21
|
+
});
|
22
|
+
});
|
23
|
+
|
24
|
+
describe('publicPath', () => {
|
25
|
+
it('defaults to http://localhost:3001/assets', () => {
|
26
|
+
const config = utils.extractDevServerConfig({});
|
27
|
+
expect(config.publicPath).toBe('http://localhost:3001/assets');
|
28
|
+
});
|
29
|
+
|
30
|
+
it('leaves a full URL intact', () => {
|
31
|
+
Object.assign(projectConfig.devServer, { host: 'hauler.test', port: 8080 });
|
32
|
+
projectConfig.publicPath = 'https://my.hauler.test:4005/my-assets';
|
33
|
+
const config = utils.extractDevServerConfig(projectConfig);
|
34
|
+
expect(config.publicPath).toBe('https://my.hauler.test:4005/my-assets');
|
35
|
+
});
|
36
|
+
|
37
|
+
it('updates to a full URL', () => {
|
38
|
+
Object.assign(projectConfig.devServer, { host: 'hauler.test', port: 8080 });
|
39
|
+
projectConfig.publicPath = '/my-assets';
|
40
|
+
const config = utils.extractDevServerConfig(projectConfig);
|
41
|
+
expect(config.publicPath).toBe('http://hauler.test:8080/my-assets');
|
42
|
+
});
|
43
|
+
|
44
|
+
it('sets the protocol according to the port', () => {
|
45
|
+
Object.assign(projectConfig.devServer, { port: 80 });
|
46
|
+
let config = utils.extractDevServerConfig(projectConfig);
|
47
|
+
expect(config.publicPath).toMatch('^http://localhost/');
|
48
|
+
|
49
|
+
Object.assign(projectConfig.devServer, { port: 443 });
|
50
|
+
config = utils.extractDevServerConfig(projectConfig);
|
51
|
+
expect(config.publicPath).toMatch('^https://localhost/');
|
52
|
+
});
|
53
|
+
});
|
54
|
+
});
|
55
|
+
|
56
|
+
describe('extractCompilerConfig', () => {
|
57
|
+
let projectConfigFactory;
|
58
|
+
let projectConfig;
|
59
|
+
|
60
|
+
beforeEach(() => {
|
61
|
+
pathUtils.setRailsRoot('/var/www/hauler');
|
62
|
+
projectConfigFactory = require('../../defaults/project_config_factory').default;
|
63
|
+
projectConfig = projectConfigFactory('development');
|
64
|
+
});
|
65
|
+
|
66
|
+
it('resolves #context to railsRoot', () => {
|
67
|
+
projectConfig.compiler.context = '~';
|
68
|
+
const config = utils.extractCompilerConfig(projectConfig);
|
69
|
+
expect(config.context).toBe('/var/www/hauler/');
|
70
|
+
});
|
71
|
+
|
72
|
+
it('assigns projectConfig#entries to #entry', () => {
|
73
|
+
projectConfig.entries = { main: 'main.js' };
|
74
|
+
const config = utils.extractCompilerConfig(projectConfig);
|
75
|
+
expect(config.entry).toEqual({ main: 'main.js' });
|
76
|
+
});
|
77
|
+
|
78
|
+
it('resolves #entry to railsRoot', () => {
|
79
|
+
projectConfig.entries = { main: '~lib/assets/hauler/main.js', counter: './counter' };
|
80
|
+
const config = utils.extractCompilerConfig(projectConfig);
|
81
|
+
expect(config.entry).toEqual({
|
82
|
+
main: '/var/www/hauler/lib/assets/hauler/main.js',
|
83
|
+
counter: './counter',
|
84
|
+
});
|
85
|
+
});
|
86
|
+
|
87
|
+
it('resolves #output.path to railsRoot', () => {
|
88
|
+
projectConfig.compiler.output.path = '~public/assets';
|
89
|
+
const config = utils.extractCompilerConfig(projectConfig);
|
90
|
+
expect(config.output.path).toBe('/var/www/hauler/public/assets');
|
91
|
+
});
|
92
|
+
|
93
|
+
it('resolves #output.publicPath to a full Url using the devServer', () => {
|
94
|
+
projectConfig.publicPath = '/test-assets';
|
95
|
+
Object.assign(projectConfig.devServer, { host: 'asset-host', port: 4005 });
|
96
|
+
const config = utils.extractCompilerConfig(projectConfig);
|
97
|
+
expect(config.output.publicPath).toBe('http://asset-host:4005/test-assets');
|
98
|
+
});
|
99
|
+
|
100
|
+
describe('#module.loaders', () => {
|
101
|
+
it('extracts the loaders from the project config', () => {
|
102
|
+
Object.assign(projectConfig, {
|
103
|
+
javascriptLoader: 'js',
|
104
|
+
sassLoader: 'sass',
|
105
|
+
fontLoader: 'font',
|
106
|
+
imageLoader: 'image',
|
107
|
+
});
|
108
|
+
const config = utils.extractCompilerConfig(projectConfig);
|
109
|
+
expect(config.module.loaders).toEqual(['js', 'sass', 'font', 'image']);
|
110
|
+
});
|
111
|
+
|
112
|
+
it('removes blank loaders', () => {
|
113
|
+
Object.assign(projectConfig, {
|
114
|
+
javascriptLoader: 'js',
|
115
|
+
sassLoader: null,
|
116
|
+
fontLoader: null,
|
117
|
+
imageLoader: 'image',
|
118
|
+
});
|
119
|
+
const config = utils.extractCompilerConfig(projectConfig);
|
120
|
+
expect(config.module.loaders).toEqual(['js', 'image']);
|
121
|
+
});
|
122
|
+
|
123
|
+
it('appends loaders in #compiler.module.loaders', () => {
|
124
|
+
Object.assign(projectConfig, {
|
125
|
+
javascriptLoader: 'js', sassLoader: null, fontLoader: null, imageLoader: null,
|
126
|
+
});
|
127
|
+
projectConfig.module = { loaders: ['other'] };
|
128
|
+
const config = utils.extractCompilerConfig(projectConfig);
|
129
|
+
expect(config.module.loaders).toEqual(['js', 'other']);
|
130
|
+
});
|
131
|
+
});
|
132
|
+
});
|
@@ -0,0 +1,75 @@
|
|
1
|
+
jest.unmock('../merge_config');
|
2
|
+
|
3
|
+
const defaults = {
|
4
|
+
entries: { main: 'my-main-entry.js' },
|
5
|
+
javascriptLoader: { test: 'jsLoader' },
|
6
|
+
sassLoader: { test: 'sassLoader' },
|
7
|
+
fontLoader: { test: 'fontLoader' },
|
8
|
+
imageLoader: { test: 'imageLoader' },
|
9
|
+
prependPlugins: ['prepend'],
|
10
|
+
plugins: ['plugins'],
|
11
|
+
appendPlugins: ['append'],
|
12
|
+
publicPath: '/my-assets',
|
13
|
+
devServer: {
|
14
|
+
stats: { colors: true },
|
15
|
+
},
|
16
|
+
compiler: {
|
17
|
+
output: { filename: '[name]-[hash].js' },
|
18
|
+
module: { loaders: [{ test: /\.js$/ }] },
|
19
|
+
resolve: { alias: { xyz: '/absolute/path/to/file.js' } },
|
20
|
+
},
|
21
|
+
};
|
22
|
+
|
23
|
+
describe('mergeProjectConfig', () => {
|
24
|
+
let misc;
|
25
|
+
let utils;
|
26
|
+
|
27
|
+
beforeEach(() => {
|
28
|
+
misc = require('../misc');
|
29
|
+
misc.merge.mockReturnValue({});
|
30
|
+
|
31
|
+
utils = require('../merge_config');
|
32
|
+
});
|
33
|
+
|
34
|
+
it('merges the source into the defaults', () => {
|
35
|
+
const source = { entries: { main: 'application.js' } };
|
36
|
+
utils.mergeProjectConfig(defaults, source);
|
37
|
+
expect(misc.merge).toBeCalledWith(defaults, source);
|
38
|
+
});
|
39
|
+
|
40
|
+
it('merges the source.devServer into the defaults.devServer', () => {
|
41
|
+
const devServer = { contentBase: '/', quiet: true };
|
42
|
+
utils.mergeProjectConfig(defaults, { devServer });
|
43
|
+
expect(misc.merge).toBeCalledWith(defaults.devServer, devServer);
|
44
|
+
});
|
45
|
+
|
46
|
+
it('merges the source.devServer.stats into the defaults.devServer.stats', () => {
|
47
|
+
const stats = { hash: true };
|
48
|
+
utils.mergeProjectConfig(defaults, { devServer: { stats } });
|
49
|
+
expect(misc.merge).toBeCalledWith(defaults.devServer.stats, stats);
|
50
|
+
});
|
51
|
+
|
52
|
+
it('merges the source.compiler into the defaults.compiler', () => {
|
53
|
+
const compiler = { context: '/', cache: false };
|
54
|
+
utils.mergeProjectConfig(defaults, { compiler });
|
55
|
+
expect(misc.merge).toBeCalledWith(defaults.compiler, compiler);
|
56
|
+
});
|
57
|
+
|
58
|
+
it('merges the source.compiler.output into the defaults.compiler.output', () => {
|
59
|
+
const output = { filename: '[name].js', chunkFilename: '[name].chunk.js' };
|
60
|
+
utils.mergeProjectConfig(defaults, { compiler: { output } });
|
61
|
+
expect(misc.merge).toBeCalledWith(defaults.compiler.output, output);
|
62
|
+
});
|
63
|
+
|
64
|
+
it('merges the source.compiler.module into the defaults.compiler.module', () => {
|
65
|
+
const module = { loaders: [{ test: /\.css$/ }] };
|
66
|
+
utils.mergeProjectConfig(defaults, { compiler: { module } });
|
67
|
+
expect(misc.merge).toBeCalledWith(defaults.compiler.module, module);
|
68
|
+
});
|
69
|
+
|
70
|
+
it('merges the source.compiler.resolve into the defaults.compiler.resolve', () => {
|
71
|
+
const resolve = { alias: { xyz: './dir' } };
|
72
|
+
utils.mergeProjectConfig(defaults, { compiler: { resolve } });
|
73
|
+
expect(misc.merge).toBeCalledWith(defaults.compiler.resolve, resolve);
|
74
|
+
});
|
75
|
+
});
|
@@ -0,0 +1,26 @@
|
|
1
|
+
jest.unmock('../path');
|
2
|
+
|
3
|
+
const utils = require('../path');
|
4
|
+
|
5
|
+
describe('pathJoin', () => {
|
6
|
+
it('leaves the leading slash on the first piece', () => {
|
7
|
+
expect(utils.pathJoin('/hello', 'world')).toBe('/hello/world');
|
8
|
+
expect(utils.pathJoin('hello', 'world')).toBe('hello/world');
|
9
|
+
});
|
10
|
+
|
11
|
+
it('cleans any lagging slash', () => {
|
12
|
+
expect(utils.pathJoin('hello', 'world/')).toBe('hello/world');
|
13
|
+
});
|
14
|
+
|
15
|
+
it('removes any leading or lagging spaces', () => {
|
16
|
+
expect(utils.pathJoin(' hello ', ' world ')).toBe('hello/world');
|
17
|
+
});
|
18
|
+
|
19
|
+
it('removes duplicate slashes', () => {
|
20
|
+
expect(utils.pathJoin('hello///', '///world///')).toBe('hello/world');
|
21
|
+
});
|
22
|
+
|
23
|
+
it('ignores null pieces', () => {
|
24
|
+
expect(utils.pathJoin(null, 'hello', null, 'world', null)).toBe('hello/world');
|
25
|
+
});
|
26
|
+
});
|
@@ -0,0 +1,103 @@
|
|
1
|
+
// @flow
|
2
|
+
|
3
|
+
import url from 'url';
|
4
|
+
import { railsPath } from './path';
|
5
|
+
import { compact } from './misc';
|
6
|
+
|
7
|
+
function resolveValuesRailsPath(entries: Object = {}): Object {
|
8
|
+
const keys = Object.keys(entries);
|
9
|
+
const reducer = (output, key) => Object.assign(output, { [key]: railsPath(entries[key]) });
|
10
|
+
return keys.reduce(reducer, {});
|
11
|
+
}
|
12
|
+
|
13
|
+
function extractLoaders(config: ProjectConfig): Array<WebpackLoader> {
|
14
|
+
const baseLoaders = compact([
|
15
|
+
config.javascriptLoader,
|
16
|
+
config.sassLoader,
|
17
|
+
config.fontLoader,
|
18
|
+
config.imageLoader,
|
19
|
+
]);
|
20
|
+
|
21
|
+
const customLoaders = config.module && config.module.loaders || [];
|
22
|
+
return baseLoaders.concat(customLoaders);
|
23
|
+
}
|
24
|
+
|
25
|
+
function extractResolve(config: ProjectConfig): WebpackResolveConfig {
|
26
|
+
const resolveConfig = config.compiler && config.compiler.resolve || {};
|
27
|
+
return Object.assign(resolveConfig, {
|
28
|
+
alias: resolveValuesRailsPath(resolveConfig.alias),
|
29
|
+
root: railsPath(resolveConfig.root),
|
30
|
+
});
|
31
|
+
}
|
32
|
+
|
33
|
+
function extractPlugins(config: ProjectConfig): Array<WebpackPlugin> {
|
34
|
+
const prepend = config.prependPlugins || [];
|
35
|
+
const plugins = config.plugins || [];
|
36
|
+
const appendPlugins = config.appendPlugins || [];
|
37
|
+
return prepend.concat(plugins).concat(appendPlugins);
|
38
|
+
}
|
39
|
+
|
40
|
+
function extractModule(config: ProjectConfig): WebpackModuleConfig {
|
41
|
+
const moduleConfig = config.compiler && config.compiler.module || {};
|
42
|
+
return Object.assign(moduleConfig, {
|
43
|
+
loaders: extractLoaders(config),
|
44
|
+
});
|
45
|
+
}
|
46
|
+
|
47
|
+
function formatUrl(urlObject: Object) {
|
48
|
+
return url.format(urlObject);
|
49
|
+
}
|
50
|
+
|
51
|
+
function extractPublicPath(config: ProjectConfig): string {
|
52
|
+
const pathUrl = url.parse(config.publicPath || '/assets');
|
53
|
+
const port = String(config.devServer && config.devServer.port || '3001');
|
54
|
+
|
55
|
+
if (!pathUrl.protocol) {
|
56
|
+
pathUrl.protocol = port === '443' ? 'https' : 'http';
|
57
|
+
}
|
58
|
+
|
59
|
+
if (!pathUrl.hostname) {
|
60
|
+
pathUrl.hostname = config.devServer && config.devServer.host || 'localhost';
|
61
|
+
}
|
62
|
+
|
63
|
+
if (!pathUrl.port && port !== '80' && port !== '443') {
|
64
|
+
pathUrl.port = port;
|
65
|
+
}
|
66
|
+
|
67
|
+
return formatUrl(pathUrl);
|
68
|
+
}
|
69
|
+
|
70
|
+
function extractOutput(config: ProjectConfig): WebpackOutputConfig {
|
71
|
+
const outputConfig = config.compiler && config.compiler.output || {};
|
72
|
+
return Object.assign(outputConfig, {
|
73
|
+
path: railsPath(outputConfig.path),
|
74
|
+
publicPath: extractPublicPath(config),
|
75
|
+
});
|
76
|
+
}
|
77
|
+
|
78
|
+
function resolveContentBase(contentBase?: string): ?string {
|
79
|
+
if (!contentBase) {
|
80
|
+
return undefined;
|
81
|
+
}
|
82
|
+
|
83
|
+
return railsPath(contentBase);
|
84
|
+
}
|
85
|
+
|
86
|
+
export function extractCompilerConfig(config: ProjectConfig): WebpackConfig {
|
87
|
+
const compilerConfig = Object.assign({}, config.compiler);
|
88
|
+
return Object.assign({}, compilerConfig, {
|
89
|
+
context: railsPath(compilerConfig.context),
|
90
|
+
entry: resolveValuesRailsPath(config.entries),
|
91
|
+
output: extractOutput(config),
|
92
|
+
module: extractModule(config),
|
93
|
+
resolve: extractResolve(config),
|
94
|
+
plugins: extractPlugins(config),
|
95
|
+
});
|
96
|
+
}
|
97
|
+
|
98
|
+
export function extractDevServerConfig(config: ProjectConfig): WebpackDevServerConfig {
|
99
|
+
return Object.assign({}, config.devServer, {
|
100
|
+
contentBase: resolveContentBase(config.devServer && config.devServer.contentBase),
|
101
|
+
publicPath: extractPublicPath(config),
|
102
|
+
});
|
103
|
+
}
|
data/src/utils/index.js
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
// @flow
|
2
|
+
|
3
|
+
import * as misc from './misc';
|
4
|
+
|
5
|
+
function mergeCompilerConfig(
|
6
|
+
target: WebpackConfig = {},
|
7
|
+
source: WebpackConfig = {}
|
8
|
+
): WebpackConfig {
|
9
|
+
const output = misc.merge(target, source);
|
10
|
+
return Object.assign(output, {
|
11
|
+
output: misc.merge(target.output, source.output),
|
12
|
+
module: misc.merge(target.module, source.module),
|
13
|
+
resolve: misc.merge(target.resolve, source.resolve),
|
14
|
+
});
|
15
|
+
}
|
16
|
+
|
17
|
+
function mergeDevServerConfig(
|
18
|
+
target: WebpackDevServerConfig = {},
|
19
|
+
source: WebpackDevServerConfig = {}
|
20
|
+
): WebpackDevServerConfig {
|
21
|
+
const output = misc.merge(target, source);
|
22
|
+
return Object.assign(output, {
|
23
|
+
stats: misc.merge(target.stats, source.stats),
|
24
|
+
});
|
25
|
+
}
|
26
|
+
|
27
|
+
export function mergeProjectConfig(target: ProjectConfig, source: ProjectConfig): ProjectConfig {
|
28
|
+
const output = misc.merge(target, source);
|
29
|
+
return Object.assign(output, {
|
30
|
+
entries: source.entries || target.entries || {},
|
31
|
+
devServer: mergeDevServerConfig(target.devServer, source.devServer),
|
32
|
+
compiler: mergeCompilerConfig(target.compiler, source.compiler),
|
33
|
+
});
|
34
|
+
}
|