@@ -8,40 +8,40 @@ var url = require('url');
8
8
var paths = require ( './paths' ) ;
9
9
var getClientEnvironment = require ( './env' ) ;
10
10
11
- function ensureSlash ( path , needsSlash ) {
12
- var hasSlash = path . endsWith ( '/' ) ;
13
- if ( hasSlash && ! needsSlash ) {
14
- return path . substr ( path , path . length - 1 ) ;
15
- } else if ( ! hasSlash && needsSlash ) {
16
- return path + '/' ;
17
- } else {
18
- return path ;
19
- }
20
- }
21
11
22
- // We use "homepage" field to infer "public path" at which the app is served.
23
- // Webpack needs to know it to put the right <script> hrefs into HTML even in
24
- // single-page apps that may serve index.html for nested URLs like /todos/42.
25
- // We can't use a relative path in HTML because we don't want to load something
26
- // like /todos/42/static/js/bundle.7289d.js. We have to know the root.
27
- var homepagePath = require ( paths . appPackageJson ) . homepage ;
28
- var homepagePathname = homepagePath ? url . parse ( homepagePath ) . pathname : '/' ;
12
+
29
13
// Webpack uses `publicPath` to determine where the app is being served from.
30
14
// It requires a trailing slash, or the file assets will get an incorrect path.
31
- var publicPath = ensureSlash ( homepagePathname , true ) ;
15
+ var publicPath = paths . servedPath ;
16
+ // Some apps do not use client-side routing with pushState.
17
+ // For these, "homepage" can be set to "." to enable relative asset paths.
18
+ var shouldUseRelativeAssetPaths = publicPath === './' ;
32
19
// `publicUrl` is just like `publicPath`, but we will provide it to our app
33
20
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
34
- // Omit trailing slash as %PUBLIC_PATH %/xyz looks better than %PUBLIC_PATH %xyz.
35
- var publicUrl = ensureSlash ( homepagePathname , false ) ;
21
+ // Omit trailing slash as %PUBLIC_URL %/xyz looks better than %PUBLIC_URL %xyz.
22
+ var publicUrl = publicPath . slice ( 0 , - 1 ) ;
36
23
// Get environment variables to inject into our app.
37
24
var env = getClientEnvironment ( publicUrl ) ;
38
25
39
26
// Assert this just to be safe.
40
27
// Development builds of React are slow and not intended for production.
41
- if ( env [ 'process.env' ] . NODE_ENV !== '"production"' ) {
28
+ if ( env . stringified [ 'process.env' ] . NODE_ENV !== '"production"' ) {
42
29
throw new Error ( 'Production builds must have NODE_ENV=production.' ) ;
43
30
}
44
31
32
+ // Note: defined here because it will be used more than once.
33
+ const cssFilename = 'static/css/[name].[contenthash:8].css' ;
34
+
35
+ // ExtractTextPlugin expects the build output to be flat.
36
+ // (See https://github.com/webpack-contrib/extract-text-webpack-plugin/issues/27)
37
+ // However, our output is structured with css, js and media folders.
38
+ // To have this structure working with relative paths, we have to use custom options.
39
+ const extractTextPluginOptions = shouldUseRelativeAssetPaths
40
+ // Making sure that the publicPath goes back to to build folder.
41
+ ? { publicPath : Array ( cssFilename . split ( '/' ) . length ) . join ( '../' ) }
42
+ : undefined ;
43
+
44
+
45
45
// This is the production configuration.
46
46
// It compiles slowly and is focused on producing a fast and minimal bundle.
47
47
// The development configuration is different and lives in a separate file.
@@ -97,25 +97,22 @@ module.exports = {
97
97
}
98
98
] ,
99
99
loaders : [
100
- // Default loader: load all assets that are not handled
101
- // by other loaders with the url loader.
102
- // Note: This list needs to be updated with every change of extensions
103
- // the other loaders match.
104
- // E.g., when adding a loader for a new supported file extension,
105
- // we need to add the supported extension to this loader too.
106
- // Add one new line in `exclude` for each loader.
107
- //
108
- // "file" loader makes sure those assets end up in the `build` folder.
109
- // When you `import` an asset, you get its filename.
110
- // "url" loader works just like "file" loader but it also embeds
111
- // assets smaller than specified size as data URLs to avoid requests.
100
+ // ** ADDING/UPDATING LOADERS **
101
+ // The "url" loader handles all assets unless explicitly excluded.
102
+ // The `exclude` list *must* be updated with every change to loader extensions.
103
+ // When adding a new loader, you must add its `test`
104
+ // as a new entry in the `exclude` list in the "url" loader.
105
+
106
+ // "url" loader embeds assets smaller than specified size as data URLs to avoid requests.
107
+ // Otherwise, it acts like the "file" loader.
112
108
{
113
109
exclude : [
114
110
/ \. h t m l $ / ,
115
111
/ \. ( j s | j s x ) $ / ,
116
- / \. l e s s $ / ,
117
112
/ \. c s s $ / ,
118
- / \. j s o n $ /
113
+ / \. j s o n $ / ,
114
+ / \. s v g $ / ,
115
+ / \. l e s s $ /
119
116
] ,
120
117
loader : 'url' ,
121
118
query : {
@@ -144,17 +141,13 @@ module.exports = {
144
141
// in the main CSS file.
145
142
{
146
143
test : / \. c s s $ / ,
147
- loader : ExtractTextPlugin . extract ( 'style' , 'css?importLoaders=1!postcss' )
144
+ loader : ExtractTextPlugin . extract (
145
+ 'style' ,
146
+ 'css?importLoaders=1!postcss' ,
147
+ extractTextPluginOptions
148
+ )
148
149
// Note: this won't work without `new ExtractTextPlugin()` in `plugins`.
149
150
} ,
150
- {
151
- test : / \. l e s s $ / ,
152
- loader : ExtractTextPlugin . extract ( 'style' , 'css?-autoprefixer!less!postcss' )
153
- } ,
154
- {
155
- test : / \. s c s s $ / ,
156
- loader : ExtractTextPlugin . extract ( 'style' , 'css?-autoprefixer!sass!postcss' )
157
- } ,
158
151
// JSON is not enabled by default in Webpack but both Node and Browserify
159
152
// allow it implicitly so we also enable it.
160
153
{
@@ -168,6 +161,14 @@ module.exports = {
168
161
query : {
169
162
name : 'static/media/[name].[hash:8].[ext]'
170
163
}
164
+ } ,
165
+ {
166
+ test : / \. l e s s $ / ,
167
+ loader : ExtractTextPlugin . extract ( 'style' , 'css?-autoprefixer!less!postcss' )
168
+ } ,
169
+ {
170
+ test : / \. s c s s $ / ,
171
+ loader : ExtractTextPlugin . extract ( 'style' , 'css?-autoprefixer!sass!postcss' )
171
172
}
172
173
]
173
174
} ,
@@ -190,9 +191,7 @@ module.exports = {
190
191
// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
191
192
// In production, it will be an empty string unless you specify "homepage"
192
193
// in `package.json`, in which case it will be the pathname of that URL.
193
- new InterpolateHtmlPlugin ( {
194
- PUBLIC_URL : publicUrl
195
- } ) ,
194
+ new InterpolateHtmlPlugin ( env . raw ) ,
196
195
// Generates an `index.html` file with the <script> injected.
197
196
new HtmlWebpackPlugin ( {
198
197
inject : true ,
@@ -214,7 +213,7 @@ module.exports = {
214
213
// if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`.
215
214
// It is absolutely essential that NODE_ENV was set to production here.
216
215
// Otherwise React will be compiled in the very slow development mode.
217
- new webpack . DefinePlugin ( env ) ,
216
+ new webpack . DefinePlugin ( env . stringified ) ,
218
217
// This helps ensure the builds are consistent if source hasn't changed:
219
218
new webpack . optimize . OccurrenceOrderPlugin ( ) ,
220
219
// Try to dedupe duplicated modules, if any:
@@ -234,7 +233,7 @@ module.exports = {
234
233
}
235
234
} ) ,
236
235
// Note: this won't work without ExtractTextPlugin.extract(..) in `loaders`.
237
- new ExtractTextPlugin ( 'static/css/[name].[contenthash:8].css' ) ,
236
+ new ExtractTextPlugin ( cssFilename ) ,
238
237
// Generate a manifest file which contains a mapping of all asset filenames
239
238
// to their corresponding output file so that tools can pick it up without
240
239
// having to parse `index.html`.
0 commit comments