官术网_书友最值得收藏!

Building for production

So far, we’ve been entirely focused on using Webpack in a development context, but we also need to think about deploying our app to production, and what that may involve.

When we send our app out to the World Wide Web, we don’t want to send anything unnecessary (remember that our goal is performance); we want to deploy the bare minimum.

Here’s what we need:

  • An index.html page (minified)
  • A CSS file (minified)
  • A JavaScript file (minified)
  • All image assets
  • An asset manifest (a list of the preceding static files)

We have some of these, but not all. Let’s work on using Webpack to automatically generate a build folder with all of these, which we can deploy later.

First, a minified index.html. We want Webpack to take our public/index.html file, minify it, add the appropriate script and CSS links automatically, and then add that to a build folder.

Since our Webpack process for production will be different from development, let’s make a duplicate of our webpack.config.js and name it webpack.config.prod.js. For most of the rest of the chapter, we’ll work with webpack.config.prod.js, not webpack.config.js.

First things first, delete the devServer key from webpack.config.prod.js. We won't use a Dev server in production, nor will we use hot reloading. We need to delete the two devServer specific lines under entry, and the hot reloading line, so that it now looks like this:

 

entry: __dirname + "/src/index.js",

Also, inside our webpack.config.prod.js, let’s specify that our output folder is now chatastrophe/build by changing this line under output:

 

path: __dirname + "/public",

It needs to be changed to this:

 

path: __dirname + "/build",

We'll also want to add a publicPath, so our index.html in build will know to look for the bundled JavaScript in the same folder:

output: {
path: __dirname + "/build",
filename: "bundle.js",
publicPath: './'
},

Let's set our environment to production so that React doesn't display its (helpful, in development) warnings. We can also remove HotModuleReplacementPlugin:

plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production')
}
}),
],

Next, we will use a new Webpack plugin, called HtmlWebpackPlugin. It does what it sounds like--packs down HTML for us! Let’s install it with yarn add html-webpack-plugin, and then add it with the following options:

plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production')
}
}),
new HtmlWebpackPlugin({
inject: true,
template: __dirname + "/public/index.html",
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
}),
],

Don’t forget to require it at the top of webpack.config.prod.js, just like we required Webpack:

var HtmlWebpackPlugin = require('html-webpack-plugin');

Time to give it a test! In your package.json, update our build script to use our new config, as follows:

"build": "node_modules/.bin/webpack --config webpack.config.prod.js",

Then, run yarn build.

You should see a build folder appear in your project directory. If you open build/index.html, you’ll see that it’s nice and mushed together. However, there’s a problem; in that squashed code, you should see two script tags, both requiring bundle.js.

That is the result of the inject option we specified earlier with HtmlWebpackPlugin. The plugin adds the script tag for us! How convenient, except that we already added it in public/index.html ourselves.

Here's a simple solution--let’s copy our HtmlWebpackPlugin configuration (and require statement) over to webpack.config.js (our original configuration file). However, we can remove the minify key and all its options, since that’s not necessary in development:

// webpack.config.js
plugins: [
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
inject: true,
template: __dirname + '/public/index.html',
})
],

Then, delete the script tag from public/index.html and try yarn start again to test whether our development environment is working, and yarn build to test our production build.

Okay, we have a minified HTML file in our build, and we have improved our development start process a bit as well. The next task is to ensure that our CSS is minified and copied into our build folder as well.

In our webpack configuration (both production and development), we used babel-loader to load our JavaScript files in; we will do something similar with CSS.

To do so, we will combine two loaders: css-loader and style-loader.

You can read more about why it’s recommended to use both on the style-loader GitHub page at https://github.com/webpack-contrib/style-loader.

Install both with the following:

 yarn add css-loader style-loader

Let’s add them to both our webpack.config.prod.js and webpack.config.js, by adding the following code under our babel-loader configuration:

What these plugins do is take a CSS file required by our React code and turn it into a <style> tag injected into our HTML. Right now, that won’t do much for us, since our CSS is sitting in our public/assets folder. Let’s move it to src, then require it in App.js:

import React from 'react';
import './app.css';

const App = () => {
return <h1>Hello from React!!</h1>
};

export default App;

Then, we can delete our link tag from our public/index.html and restart our server.

If we inspect the head of our HTML in our browser, we should see a <style> tag with all our CSS inside. Neat!:

Now, you may notice when we refresh the page, that there’s a flash of unstyled content; this is a consequence of our app now requiring React to boot up before adding styling. We’ll address that issue in the coming chapters, rest assured.

Run yarn build and take a look at bundle.js. If you search for "Start initial styles" you’ll see where our CSS is bundled in our JavaScript. Also, note how relatively readable our JavaScript is compared to our HTML. The next step is to take care of minifying it!

Fortunately, doing so is quite easy. We just add another Webpack plugin to our production file. After HtmlWebpackPlugin, add the following:

plugins: [
new HtmlWebpackPlugin({
inject: true,
template: __dirname + '/public/index.html',
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true
}
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
reduce_vars: false
},
output: {
comments: false
},
sourceMap: true
})
]

Run yarn build again, and you should see that our bundle.js has become a single line. This is not great for humans, but much faster for the browser.

Okay, we're getting closer to the end. Next, we want to ensure that all our asset files get copied over to our build folder.

We can do so by adding another loader to our Webpack config, called file-loader. We’ll install it with yarn add file-loader@0.11.2. Let’s see what the code looks like (note that this is only for our webpack.config.prod.js file):

module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015', 'react'],
plugins: ['react-hot-loader/babel', 'transform-class-properties']
}
},
{
test: /\.css$/,
use: [{ loader: 'style-loader' }, { loader: 'css-loader' }]
},
{
exclude: [/\.html$/, /\.(js|jsx)$/, /\.css$/, /\.json$/],
loader: 'file-loader',
options: {
name: 'static/media/[name].[ext]'
}
}</strong>
]
},

Note that we’re excluding HTML, CSS, JSON, and JS files. These are covered by our other loaders, so we don’t want to duplicate files.

We’re also putting these assets in a static folder, just like our assets folder in our public folder.

However, file-loader will only apply to those files required by our JavaScript code. We have our favicon and icon, which are currently only used in our index.html, so Webpack won't find them.

To do so, we will use JavaScript instead of Webpack (since Webpack focuses only on our src folder).

主站蜘蛛池模板: 分宜县| 山东| 河曲县| 石楼县| 嵊泗县| 璧山县| 九龙坡区| 淳化县| 石河子市| 永寿县| 丹阳市| 宿松县| 芮城县| 兴安盟| 个旧市| 云龙县| 旌德县| 新和县| 罗田县| 孙吴县| 白银市| 揭阳市| 永济市| 南充市| 龙江县| 博客| 枣阳市| 抚顺县| 灵宝市| 沂水县| 景宁| 本溪市| 顺昌县| 铜梁县| 通海县| 教育| 龙胜| 勐海县| 临桂县| 宜君县| 和田市|