如何将Webpack与React结合使用:深入的教程

 2023-09-06 阅读 19 评论 0

摘要:Updated to Babel 7 更新至Babel 7 In this tutorial we will see the basics of Webpack for React to get you started, including React Router, Hot Module Replacement (HMR), Code Splitting by Route and Vendor, production configuration and more. 在本教程中࿰

Updated to Babel 7

更新至Babel 7

In this tutorial we will see the basics of Webpack for React to get you started, including React Router, Hot Module Replacement (HMR), Code Splitting by Route and Vendor, production configuration and more.

在本教程中,我们将了解Webpack for React的基础知识,包括React Router , 热模块替换 (HMR),按路线和供应商进行代码拆分,生产配置等。

Before we start, here’s the full list of features we are going to set up together in this tutorial:

在开始之前,这是我们将在本教程中一起设置的功能的完整列表:

  • React 16

    React16
  • React Router 5

    React路由器5
  • Semantic UI as the CSS Framework

    语义UI作为CSS框架
  • Hot Module Replacement (HMR)

    热模块更换(HMR)
  • CSS Autoprefixer

    CSS自动前缀
  • CSS Modules

    CSS模块
  • @babel/plugin-proposal-class-properties

    @ babel / plugin-proposal-class-properties
  • @babel/plugin-syntax-dynamic-import

    @ babel / plugin-syntax-dynamic-import
  • Webpack 4

    Webpack 4
  • Code Splitting by Route and Vendor

    按路线和供应商划分代码
  • Webpack Bundle Analyzer

    Webpack捆绑分析器

先决条件 (Pre-requisites)

Have the following pre-installed:

预先安装以下内容:

  • Yarn — Package manager, similar to npm

    Yarn —程序包管理器,类似于npm

  • Node

    节点

And you should have at least some basic knowledge of React and React Router.

并且您至少应具备React和React Router的一些基本知识。

Note: You can use npm if you wish, although the commands will vary slightly.

注意: 您可以根据需要使用npm,尽管命令会略有不同。

初始依赖 (Initial Dependencies)

Let us start by creating our directory and package.json.

让我们从创建目录和package.json

In your terminal type the following:

在终端中输入以下内容:

mkdir webpack-for-react && cd $_
yarn init -y

This first command will create our directory and move into it, then we initialize a package.json accepting defaults. If you inspect it you will see the bare bones configuration:

第一个命令将创建我们的目录并移至该目录,然后初始化一个接受默认值的package.json 。 如果您检查它,将会看到裸露的配置:

{"name": "webpack-for-react","version": "1.0.0","main": "index.js","license": "MIT"
}

Now we install our initial (production) dependencies and development dependencies. In your terminal type the following:

现在,我们安装初始(生产)依赖关系和开发依赖关系。 在终端中输入以下内容:

yarn add react react-dom prop-types react-router-dom semantic-ui-react
yarn add @babel/core babel-loader @babel/preset-env @babel/preset-react @babel/plugin-proposal-class-properties @babel/plugin-syntax-dynamic-import css-loader style-loader html-webpack-plugin webpack webpack-dev-server webpack-cli -D

The development dependencies will only be used, as implied, during the development phase, and the (production) dependencies is what our application needs in production.

开发依赖关系仅在开发阶段才会使用,(生产)依赖关系是我们的应用程序在生产中所需要的。

{"name": "webpack-for-react","version": "1.0.0","main": "index.js","license": "MIT","dependencies": {"react": "^16.2.0","react-dom": "^16.2.0","prop-types": "^15.6.2","react-router-dom": "^4.2.2","semantic-ui-react": "^0.77.1"},"devDependencies": {"@babel/core": "^7.0.0","@babel/plugin-proposal-class-properties": "^7.0.0","@babel/plugin-syntax-dynamic-import": "^7.0.0","@babel/preset-env": "^7.0.0","@babel/preset-react": "^7.0.0", "babel-loader": "^8.0.1","css-loader": "^0.28.10","html-webpack-plugin": "^3.0.4","style-loader": "^0.19.1","webpack": "^4.0.0","webpack-cli": "^2.0.14","webpack-dev-server": "^3.0.0"}
}

Note: Changes to previously created files will be bolded.Note: Dependencies versions might be different than yours from the time of this writing.

注意: 对先前创建的文件所做的更改将以粗体显示。 注意: 从撰写本文之日起,依赖项版本可能与您的依赖项版本不同。

  • react — I’m sure you know what React is

    React —我确定你知道React是什么

  • react-dom — Provides DOM-specific methods for the browser

    react-dom-为浏览器提供特定于DOM的方法

  • prop-types — Runtime type checking for React props

    prop-types -React props的运行时类型检查

  • react-router-dom — Provides routing capabilities to React for the browser

    react-router- dom-为浏览器的React提供路由功能

  • semantic-ui-react — CSS Framework

    语义用户界面React — CSS框架

  • @babel/core — Core dependencies for Babel

    @ babel / core — Babel的核心依赖项

  • Babel is a transpiler that compiles JavaScript ES6 to JavaScript ES5 allowing you to write JavaScript “from the future” so that current browsers will understand it. Detailed description in Quora.

    Babel是一个编译器,可以将JavaScript ES6编译为JavaScript ES5,使您可以“从未来”编写JavaScript,以便当前的浏览器可以理解。 Quora中的详细描述 。

  • babel-loader — This package allows transpiling JavaScript files using Babel and webpack

    babel- loader-此软件包允许使用Babel和webpack转换JavaScript文件

  • @babel/preset-env — With this you don’t have to specify if you will be writing ES2015, ES2016 or ES2017. Babel will automatically detect and transpile accordingly.

    @ babel / preset-env —无需指定要编写ES2015,ES2016或ES2017。 Babel将自动检测并进行相应的运输。

  • @babel/preset-react — Tells Babel we will be using React

    @ babel / preset-react —告诉Babel我们将使用React

  • @babel/plugin-proposal-class-properties — Use class properties. We don’t use Class Properties in this project, but you will more than likely use them in your project

    @ babel / plugin-proposal-class-properties-使用类属性。 我们不在此项目中使用类属性,但您很有可能在项目中使用它们

  • @babel/plugin-syntax-dynamic-import — Be able to use dynamic imports

    @ babel / plugin-syntax-dynamic- import-能够使用动态导入

  • css-loader — Interprets @import and url() like import/require() and will resolve them

    css-loader —像我mport/require()一样解释@importurl()并将解析它们

  • html-webpack-plugin — Can generate an HTML file for your application, or you can provide a template

    html-webpack-plugin —可以为您的应用程序生成HTML文件,也可以提供模板

  • style-loader — Adds CSS to the DOM by injecting a <style> tag

    style-loader —通过注入<sty le>标签将CSS添加到DOM

  • webpack — Module bundler

    webpack —模块捆绑器

  • webpack-cli — Command Line Interface, needed for Webpack 4.0.1 and latest

    webpack-cli — Webpack 4.0.1和最新版本所需的命令行界面

  • webpack-dev-server — Provides a development server for your application

    webpack-dev-server —为您的应用程序提供开发服务器

设置Babel (Setting up Babel)

In the root directory (webpack-for-react) we create the Babel configuration file.

在根目录( webpack-for-react )中,我们创建Babel配置文件。

touch .babelrc

At this point you can open your favorite editor (mine is VS Code by the way), then point the editor to the root of this project and open .babelrc file and copy the following:

此时,您可以打开自己喜欢的编辑器(顺便说一下,我的代码是VS Code),然后将编辑器指向该项目的根目录并打开.babelrc文件并复制以下内容:

{"presets": ["@babel/preset-env", "@babel/preset-react"],"plugins": ["@babel/plugin-syntax-dynamic-import","@babel/plugin-proposal-class-properties"]
}

This tells Babel to use the presets (plugins) we previously installed. Later when we call babel-loader from Webpack, this is where it will look to know what to do.

这告诉Babel使用我们先前安装的预设(插件)。 稍后,当我们从Webpack调用babel-loader ,它将在这里知道要做什么。

设置Webpack (Setting up Webpack)

Now the fun begins! Let’s create the Webpack configuration file.

现在,乐趣开始了! 让我们创建Webpack配置文件。

In your terminal type the following:

在终端中输入以下内容:

touch webpack.config.js

Open webpack.config.js and copy the following:

打开webpack.config.js并复制以下内容:

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');const port = process.env.PORT || 3000;module.exports = {// Webpack configuration goes here
};

This is the basic shell for Webpack. We require webpack and html-webpack-plugin. Provide a default port if the environment variable PORT does not exist and export the module.

这是Webpack的基本外壳 。 我们需要webpackhtml-webpack-plugin 。 如果环境变量PORT不存在,请提供默认端口并导出模块。

The following will be additions for webpack.config.js (one after another).

以下是webpack.config.js附加webpack.config.js (一个接一个)。

...
module.exports = {mode: 'development',
};

mode tells Webpack this configuration will be for either development or production. “Development Mode [is] optimized for speed and developer experience… Production defaults will give you a set of defaults useful for deploying your application (webpack 4: mode and optimization)”.

mode告诉Webpack此配置将用于developmentproduction 。 “开发模式已针对速度和开发人员的体验进行了优化……生产默认设置将为您提供一组默认设置,这些设置对于部署应用程序非常有用( Webpack 4:模式和优化 )”。

...
module.exports = {entry: './src/index.js',output: {filename: 'bundle.[hash].js'},
};

To get a running instance of Webpack we need:

要获取正在运行的Webpack实例,我们需要:

  • entry — Specifies the entry point of your application; this is where your React app lives and where the bundling process will begin (Docs)

    entry —指定应用程序的入口点; 这是您的React应用程序居住的地方,并且捆绑过程将在此开始( Docs )

Webpack 4 introduced some defaults, so if you don’t include entry in your configuration, then Webpack will assume your entry point is located under the ./src directory, making entry optional as opposed to Webpack 3. For this tutorial I have decided to leave entry as it makes it obvious where our entry point will be, but you are more than welcome to remove it if you so decide.

Webpack 4引入了一些默认值,因此,如果您在配置中不包括entry ,则Webpack将假定您的入口点位于./src目录下,从而使entry可选的,而不是Webpack3。对于本教程,我决定离开entry因为它使我们的进入点很明显,但是如果您决定这样做,欢迎您删除它。

  • output — Tells Webpack how to write the compiled files to disk (Docs)

    output -告诉Webpack如何将已编译的文件写入磁盘( Docs )

  • filename — This will be the filename of the bundled application. The [hash] portion of the filename will be replaced by a hash generated by Webpack every time your application changes and is recompiled (helps with caching).

    filename这将是捆绑应用程序的文件名。 每次您的应用程序更改并重新编译时,文件名的[hash]部分将由Webpack生成的哈希替换(帮助缓存)。

...
module.exports = {...devtool: 'inline-source-map',
};

devtool will create source maps to help you with debugging of your application. There are several types of source maps and this particular map (inline-source-map) is to be used only in development. (Refer to the docs for more options).

devtool将创建源映射,以帮助您调试应用程序。 有几种类型的源映射,此特定映射( inline-source-map )仅在开发中使用。 (有关更多选项,请参阅文档 )。

...
module.exports = {...module: {rules: [// First Rule{test: /\.(js)$/,exclude: /node_modules/,use: ['babel-loader']},// Second Rule{test: /\.css$/,use: [{loader: 'style-loader'},{loader: 'css-loader',options: {modules: true,localsConvention: 'camelCase',sourceMap: true}}]}]},
};
  • module — What types of modules your application will include, in our case we will support ESNext (Babel) and CSS Modules

    模块 -什么类型的模块的应用程序将包括,在我们的例子中,我们将支持ESNext(巴贝尔)和CSS模块

  • rules — How we handle each different type of module

    规则 —我们如何处理每种不同类型的模块

第一法则 (First Rule)

We test for files with a .js extension excluding the node_modules directory and use Babel, via babel-loader, to transpile down to vanilla JavaScript (basically, looking for our React files).

我们测试扩展名为.js文件(不包括node_modules目录),并通过babel-loader使用Babel将其node_modules为原始JavaScript(基本上是在寻找我们的React文件)。

Remember our configuration in .babelrc? This is where Babel looks at that file.

还记得我们在.babelrc的配置吗? 这是Babel查看该文件的地方。

第二条规则 (Second Rule)

We test for CSS files with a .css extension. Here we use two loaders, style-loader and css-loader, to handle our CSS files. Then we instruct css-loader to use CSS Modules, camel case and create source maps.

我们测试扩展名为.css CSS文件。 在这里,我们使用两个加载style-loadercss-loader来处理我们CSS文件。 然后,我们指示css-loader使用CSS模块 ,驼峰式保护套并创建源映射。

CSS Modules and Camel Case

CSS模块和骆驼盒

This gives us the ability to use import Styles from ‘./styles.css’ syntax (or destructuring like this import { style1, style2 } from ‘./styles.css’).

这使我们能够使用import Styles from './styles.css'语法的import Styles from './styles.css' (或import Styles from './styles.css'这种import { style1, style2 } from './styles.css' )。

Then we can use it like this in a React app:

然后我们可以在React应用中像这样使用它:

...
<div className={Style.style1}>Hello World</div>
// or with the destructuring syntax
<div className={style1}>Hello World</div>
...

Camel case gives us the ability to write our CSS rules like this:

驼峰式案例使我们能够编写如下CSS规则:

.home-button {...}

And use it in our React files like this:

并在我们的React文件中使用它,如下所示:

...
import { homeButton } from './styles.css'
...
...
module.exports = {...plugins: [new HtmlWebpackPlugin({template: 'public/index.html',favicon: 'public/favicon.ico'})],
};

This section is where we configure (as the name implies) plugins.

这部分是我们配置(顾名思义)插件的地方。

html-webpack-plugin accepts an object with different options. In our case we specify the HTML template we will be using and the favicon. (Refer to the docs for more options).

html-webpack-plugin接受带有不同选项的对象。 在本例中,我们指定了将要使用HTML模板和favicon。 (有关更多选项,请参阅文档 )。

Later we will be adding other plugins for Bundle Analyzer and HMR.

稍后,我们将为Bundle Analyzer和HMR添加其他插件。

...
module.exports = {...devServer: {host: 'localhost',port: port,historyApiFallback: true,open: true}
};

Finally, we configure the development server. We specify localhost as the host and assign the variable port as the port (if you remember, we assigned port 3000 to this variable). We set historyApiFallback to true and open to true. This will open the browser automatically and launch your application in http://localhost:3000. (Docs)

最后,我们配置开发服务器。 我们将localhost指定为主机,并将变量port分配为端口(如果您还记得,我们将端口3000分配给该变量)。 我们将historyApiFallback设置为true,并open为true。 这将自动打开浏览器并在http:// localhost:3000中启动您的应用程序。 ( 文档 )

Now, below is the complete Webpack configuration. (webpack.config.js):

现在,下面是完整的Webpack配置。 ( webpack.config.js ):

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');const port = process.env.PORT || 3000;module.exports = {mode: 'development',  entry: './src/index.js',output: {filename: 'bundle.[hash].js'},devtool: 'inline-source-map',module: {rules: [{test: /\.(js)$/,exclude: /node_modules/,use: ['babel-loader']},{test: /\.css$/,use: [{loader: 'style-loader'},{loader: 'css-loader',options: {modules: true,localsConvention: 'camelCase',sourceMap: true}}]}]},plugins: [new HtmlWebpackPlugin({template: 'public/index.html',favicon: 'public/favicon.ico'})],devServer: {host: 'localhost',port: port,historyApiFallback: true,open: true}
};

创建React应用 (Creating the React App)

We will be creating a simple Hello World app with three routes: a home, a page not found and a dynamic page that we will be loading asynchronously when we implement code splitting later.

我们将创建一个简单的Hello World应用程序,该应用程序具有以下三种途径: home找不到页面动态页面 ,稍后我们在实现代码拆分时将动态加载该页面

Note: Assuming you have a basic understanding of React and React Router, I will not go into many details and only highlight what’s relevant to this tutorial.

注意: 假设您对React和React Router有了基本的了解,我将不涉及很多细节,而仅强调与本教程相关的内容。

We currently have the following project structure:

我们目前有以下项目结构:

|-- node_modules
|-- .babelrc
|-- package.json
|-- webpack.config.js
|-- yarn.lock

In your terminal type the following:

在终端中输入以下内容:

mkdir public && cd $_
touch index.html

We create a public directory, move into it and also create an index.html file. Here is where we also have the favicon. You can grab it from here and copy it into public directory.

我们创建一个public目录,移入该目录,还创建一个index.html文件。 在这里我们也有favicon 。 您可以从此处获取它并将其复制到公共目录中。

Open the index.html file and copy the following:

打开index.html文件并复制以下内容:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.13/semantic.min.css"></link><title>webpack-for-react</title>
</head><body><div id="root"></div>
</body></html>

Nothing much here (just a standard HTML template) only, we are adding the Semantic UI stylesheet and also creating a div with an ID of root. This is where our React app will render.

仅在这里(仅是标准HTML模板),我们只是添加了语义UI样式表,还创建了一个ID为rootdiv 。 这是我们的React应用程序将呈现的位置。

Back to your terminal type the following:

返回您的终端,输入以下内容:

cd ..
mkdir src && cd $_
touch index.js

Open index.js and copy the following:

打开index.js并复制以下内容:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';ReactDOM.render(<App />, document.getElementById('root'));

In your terminal type the following:

在终端中输入以下内容:

mkdir components && cd $_
touch App.js Layout.js Layout.css Home.js DynamicPage.js NoMatch.js

After creating the React component files, we have the following project structure:

创建React组件文件后,我们具有以下项目结构:

|-- node_modules
|-- public|-- index.html|-- favicon.ico
|-- src|-- components|-- App.js|-- DynamicPage.js|-- Home.js|-- Layout.css|-- Layout.js|-- NoMatch.js|-- index.js
|-- .babelrc
|-- package.json
|-- webpack.config.js
|-- yarn.lock

Open App.js and copy the following:

打开App.js并复制以下内容:

import React from 'react';
import { Switch, BrowserRouter as Router, Route } from 'react-router-dom';import Home from './Home';
import DynamicPage from './DynamicPage';
import NoMatch from './NoMatch';const App = () => {return (<Router><div><Switch><Route exact path="/" component={Home} /><Route exact path="/dynamic" component={DynamicPage} /><Route component={NoMatch} /></Switch></div></Router>);
};export default App;

We create our basic “shell” with React Router and have a home, dynamic page and page not found route.

我们使用React Router创建基本的“外壳”,并具有home动态页面找不到页面的路由。

Open Layout.css and copy the following:

打开Layout.css并复制以下内容:

.pull-right {display: flex;justify-content: flex-end;
}.h1 {margin-top: 10px !important;margin-bottom: 20px !important;
}

Open Layout.js and copy the following:

打开Layout.js并复制以下内容:

import React from 'react';
import { Link } from 'react-router-dom';
import { Header, Container, Divider, Icon } from 'semantic-ui-react';import { pullRight, h1 } from './layout.css';const Layout = ({ children }) => {return (<Container><Link to="/"><Header as="h1" className={h1}>webpack-for-react</Header></Link>{children}<Divider /><p className={pullRight}>Made with <Icon name="heart" color="red" /> by Esau Silva</p></Container>);
};export default Layout;

This is our container component where we define the layout of the site. Making use of CSS Modules, we are importing two CSS rules from layout.css. Also notice how we are using camel case for pullRight.

这是我们的容器组件,我们在其中定义站点的布局。 利用CSS模块,我们从layout.css导入了两个CSS规则。 还要注意,我们如何将驼峰式大小写用于pullRight

Open Home.js and copy the following:

打开Home.js并复制以下内容:

import React from 'react';
import { Link } from 'react-router-dom';import Layout from './Layout';const Home = () => {return (<Layout><p>Hello World of React and Webpack!</p><p><Link to="/dynamic">Navigate to Dynamic Page</Link></p></Layout>);
};export default Home;

Open DynamicPage.js and copy the following:

打开DynamicPage.js并复制以下内容:

import React from 'react';
import { Header } from 'semantic-ui-react';import Layout from './Layout';const DynamicPage = () => {return (<Layout><Header as="h2">Dynamic Page</Header><p>This page was loaded asynchronously!!!</p></Layout>);
};export default DynamicPage;

Open NoMatch.js and copy the following:

打开NoMatch.js并复制以下内容:

import React from 'react';
import { Icon, Header } from 'semantic-ui-react';import Layout from './Layout';const NoMatch = () => {return (<Layout><Icon name="minus circle" size="big" /><strong>Page not found!</strong></Layout>);
};export default NoMatch;

We are done creating the React components. For a final step before running our application, open package.json and add the bolded lines:

我们已经完成了React组件的创建。 对于运行我们的应用程序之前的最后一步,请打开package.json并添加粗体行:

{"name": "webpack-for-react","version": "1.0.0","main": "index.js","license": "MIT","scripts": {"start": "webpack-dev-server"},"dependencies": {"react": "^16.2.0","react-dom": "^16.2.0","prop-types": "^0.4.0","react-router-dom": "^4.2.2","semantic-ui-react": "^0.77.1"},"devDependencies": {"@babel/core": "^7.0.0","@babel/plugin-proposal-class-properties": "^7.0.0","@babel/plugin-syntax-dynamic-import": "^7.0.0","@babel/preset-env": "^7.0.0","@babel/preset-react": "^7.0.0","babel-loader": "^8.0.1","css-loader": "^0.28.10","html-webpack-plugin": "^3.0.4","style-loader": "^0.19.1","webpack": "^4.0.0","webpack-cli": "^2.0.14","webpack-dev-server": "^3.0.0"}
}

We add the scripts key and also the start key. This will allow us to run React with the Webpack Development Server. If you don’t specify a configuration file, webpack-dev-server will look for webpack.config.js file as the default configuration entry within the root directory.

我们添加了scripts键和start键。 这将使我们能够与Webpack开发服务器一起运行React。 如果不指定配置文件,则webpack-dev-server将在根目录中查找webpack.config.js文件作为默认配置条目。

Now the moment of truth! Type the following in your terminal (remember to be in the root directory) and Yarn will call our start script.

现在是关键时刻! 在您的终端中输入以下内容(记住要在根目录中),然后Yarn将调用我们的start脚本。

yarn start

Now we have a working React app powered by our own Webpack configuration. Notice at the end of the GIF I am highlighting the bundled JavaScript file Webpack generated for us, and as we indicated in the configuration, the filename has a unique hash, bundle.d505bbab002262a9bc07.js.

现在,我们有一个可运行的React应用,该应用由我们自己的Webpack配置提供支持。 请注意,在GIF末尾,我将突出显示为我们生成的捆绑JavaScript文件Webpack,正如我们在配置中所指出的,文件名具有唯一的哈希值bundle.d505bbab002262a9bc07.js

设置热模块更换(HMR) (Setting up Hot Module Replacement (HMR))

Back to your terminal, install React Hot Loader as a development dependency.

回到您的终端,安装React Hot Loader作为开发依赖项。

yarn add react-hot-loader @hot-loader/react-dom -D

Open .babelrc and add lines 3 and 9. Don’t forget to include the comma (,) at the end of line 3:

打开.babelrc并添加第3行和第9行。请不要忘记在第3行的末尾添加逗号(,):

{"presets": [["@babel/preset-env", { "modules": false }],"@babel/preset-react"],"plugins": ["@babel/plugin-syntax-dynamic-import","@babel/plugin-proposal-class-properties","react-hot-loader/babel"]
}

Open webpack.config.js and modify it as below.

打开webpack.config.js并进行如下修改。

I’m only including the relevant code and omitting code that stayed the same for brevity.

我只包括相关的代码,为简洁起见,省略了相同的代码。

...
module.exports = {entry: './src/index.js',output: {...publicPath: '/'},resolve: {alias: {"react-dom": "@hot-loader/react-dom",},},...plugins: [new webpack.HotModuleReplacementPlugin(),...],devServer: {...hot: true}
};
  • publicPath: ‘/’ — Hot reloading won’t work as expected for nested routes without it

    publicPath: '/' -如果没有嵌套路由,热重装将无法正常工作

  • webpack.HotModuleReplacementPlugin — Prints more readable module names in the browser terminal on HMR updates

    webpack.HotModuleReplacementPlugin —在HMR更新时在浏览器终端中打印更多可读的模块名称

  • hot: true — Enable HMR on the server

    hot: true —在服务器上启用HMR

  • resolve: alias — replaces react-dom with the custom react-dom from hot-loader

    resolve: alias —用来自hot-loader的自定义react-dom替换react-dom

Open index.js and change it to the following.

打开index.js并将其更改为以下内容。

import { hot } from "react-hot-loader/root";
import React from "react";
import ReactDOM from "react-dom";
import App from "./components/App";import "./index.css";const render = (Component) =>ReactDOM.render(<Component />, document.getElementById("root"));render(hot(App));

Now we are ready to test HMR! Back in the terminal run your app, make a change, and watch as the app updates without a full-page refresh.

现在我们准备测试HMR! 回到终端,运行您的应用程序,进行更改,然后在不更新整页的情况下观看应用程序更新。

yarn start

After updating the file, the page changes without a full refresh. To show this change in the browser I select Rendering -> Paint flashing in Chrome DevTools, which highlights the areas of the page, in green, that changed. I also highlight in Terminal the change Webpack sent to the browser to make this happen.

更新文件后,页面会更改而不会完全刷新。 为了在浏览器中显示此更改,我选择了Chrome DevTools中的“ 渲染”->“绘画闪烁” ,该操作以绿色突出显示了已更改的页面区域。 我还在终端中突出显示了Webpack发送给浏览器的更改,以实现此目的。

代码分割 (Code Splitting)

With code splitting, instead of having your application in one big bundle, you can have multiple bundles each loading asynchronously or in parallel. Also you can separate vendor code from you app code which can potentially decrease loading time.

使用代码拆分 ,您可以将多个捆绑包分别异步或并行加载,而不是将应用程序捆绑在一个大捆绑包中。 您也可以将供应商代码与应用程序代码分开,这有可能减少加载时间。

按路线 (By Route)

There are several ways we can achieve code splitting by route, however in our case we will be using react-imported-component.

我们有几种方法可以实现按路线分割代码,但是在我们的情况下,我们将使用react-imported-component 。

We would also like to show a loading spinner when the user navigates to a different route. This is a good practice as we don’t want the user to just stare at a blank screen while he/she waits for the new page to load. So, we will be creating a Loading component.

当用户导航到其他路线时,我们还想显示一个加载微调框 。 这是一个好习惯,因为我们不希望用户在等待新页面加载时只盯着空白屏幕。 因此,我们将创建一个Loading组件。

However, if the new page loads really fast, we don’t want the user to see a flashing loading spinner for a couple of milliseconds, so we will delay the Loading component by 300 milliseconds. To achieve this, we will be using React-Delay-Render.

但是,如果新页面的加载速度非常快,我们不希望用户看到闪烁的加载微调器持续几毫秒,因此我们会将“ 加载”组件延迟300毫秒。 为此,我们将使用React-Delay-Render 。

Start by installing the two additional dependencies.

首先安装两个附加依赖项。

In your terminal type the following:

在终端中输入以下内容:

yarn add react-imported-component react-delay-render

Now we are going to create the Loading components.

现在,我们将创建Loading组件。

In your terminal type the following:

在终端中输入以下内容:

touch ./src/components/Loading.js

Open Loading.js and copy the following:

打开Loading.js并复制以下内容:

import React from 'react';
import { Loader } from 'semantic-ui-react';
import ReactDelayRender from 'react-delay-render';const Loading = () => <Loader active size="massive" />;export default ReactDelayRender({ delay: 300 })(Loading);

Now that we have the Loading component, open App.js and modify it as follows:

现在我们有了Loading组件,打开App.js并按如下所示App.js进行修改:

import React from 'react';
import { Switch, BrowserRouter as Router, Route } from 'react-router-dom';
import importedComponent from 'react-imported-component';import Home from './Home';
import Loading from './Loading';const AsyncDynamicPAge = importedComponent(() => import(/* webpackChunkName:'DynamicPage' */ './DynamicPage'),{LoadingComponent: Loading}
);
const AsyncNoMatch = importedComponent(() => import(/* webpackChunkName:'NoMatch' */ './NoMatch'),{LoadingComponent: Loading}
);const App = () => {return (<Router><div><Switch><Route exact path="/" component={Home} /><Route exact path="/dynamic" component={AsyncDynamicPAge} /><Route component={AsyncNoMatch} /></Switch></div></Router>);
};export default App;

This will create three bundles, or chunks, one for the DynamicPage component, one for the NoMatch component, and one for the main app.

这将创建三束,或组块,一个用于DynamicPage部件,一个用于NoMatch组分和一个用于主应用程序。

Let’s also change the bundle filename. Open webpack.config.js and change it as follows:

我们还要更改捆绑文件名。 打开webpack.config.js并进行如下更改:

...
module.exports = {...output: {filename: '[name].[hash].js',...},
}

It is time to run the app and take a look at code splitting by route in action.

现在是时候运行该应用程序,看看按实际路线进行代码拆分。

yarn start

In the GIF, I first highlight the three different chunks created by Webpack in terminal. Then I highlight that upon the app launching, only the main chuck was loaded. Finally, we see that upon clicking Navigate to Dynamic Page the chunk corresponding to this page loaded asynchronously.

在GIF中,我首先突出显示Webpack在终端中创建的三个不同的块。 然后,我强调指出,在启动应用程序时,仅加载了主卡盘。 最后,我们看到单击“ 导航到动态页面”后 ,异步加载与该页面相对应的块。

We also see that the chunk corresponding to the page not found was never loaded, saving the user bandwidth.

我们还看到与未找到页面相对应的块从未加载,从而节省了用户带宽。

由供应商 (By Vendor)

Now let’s split the application by vendor. Open webpack.config.js and make the following changes:

现在,让我们按供应商划分应用程序。 打开webpack.config.js并进行以下更改:

...
module.exports = {entry: {vendor: ['semantic-ui-react'],app: './src/index.js'},...optimization: {splitChunks: {cacheGroups: {styles: {name: 'styles',test: /\.css$/,chunks: 'all',enforce: true},vendor: {chunks: 'initial',test: 'vendor',name: 'vendor',enforce: true}}}},...
};
  • entry.vendor: [‘semantic-ui-react’] — Specifies which library we want to extract from our main app and into the vendor chunk

    entry.vendor: ['semantic-ui-react'] -指定我们要从主应用程序提取到供应商块中的库

  • optimization — if you leave out this entry, Webpack will still split your application by vendor, however I noticed the bundle sizes were big and after addding this entry, the bundle sizes were reduced significantly. (I got this from Webpack 4 migration draft CommonsChunkPlugin -> Initial vendor chunk)

    optimization -如果您省略该条目,Webpack仍将按供应商划分您的应用程序,但是我注意到捆绑包的尺寸很大,添加此条目后,捆绑包的尺寸大大减小了。 (我是从Webpack 4迁移草案 CommonsChunkPlugin->初始供应商ch unk获得的)

Note: Previously Webpack 3 made use of the CommonsChunkPlugin to split the code by vendor and/or commons, however it was deprecated in Webpack 4 and many of its features are now enabled by default. With the removal of CommonsChunkPlugin they have added optimization.splitChunks for those who need fine-grained control over their caching-strategy (See this for an in-depth explanation).

注意: 以前,Webpack 3使用CommonsChunkPlugin按供应商和/或Commons拆分代码,但是Webpack 4中已弃用该代码,并且默认情况下启用了其许多功能。 通过删除CommonsChunkPlugin他们为需要对其缓存策略进行细粒度控制的用户添加了optimization.splitChunks (请参阅此内容获得详细说明)。

In terminal, launch the app:

在终端中,启动应用程序:

yarn start

In terminal, I highlight the three previous chunks plus the new vendor chunk. Then when we inspect the HTML we see that both vendor and app chunks were loaded.

在终端中,我突出显示了之前的三个块以及新的供应商块。 然后,当我们检查HTML时,我们看到供应商和应用程序块均已加载。

Since we have made several updates to our Webpack configuration, below you will find the complete webpack.config.js file.

由于我们已经对Webpack配置进行了几次更新,因此下面将找到完整的webpack.config.js文件。

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const port = process.env.PORT || 3000;
module.exports = {mode: 'development',entry: {vendor: ['semantic-ui-react'],app: './src/index.js'},output: {filename: '[name].[hash].js'},resolve: {alias: {"react-dom": "@hot-loader/react-dom",},},devtool: 'inline-source-map',module: {rules: [{test: /\.(js)$/,exclude: /node_modules/,use: ['babel-loader']},{test: /\.css$/,use: [{loader: 'style-loader'},{loader: 'css-loader',options: {modules: true,localsConvention: 'camelCase',sourceMap: true}}]}]},optimization: {splitChunks: {cacheGroups: {styles: {name: 'styles',test: /\.css$/,chunks: 'all',enforce: true},vendor: {chunks: 'initial',test: 'vendor',name: 'vendor',enforce: true}}}},plugins: [new webpack.HotModuleReplacementPlugin(),new HtmlWebpackPlugin({template: 'public/index.html',favicon: 'public/favicon.ico'})],devServer: {host: 'localhost',port: port,historyApiFallback: true,open: true,hot: true}
};

生产配置 (Production Configuration)

Rename the Webpack configuration from webpack.config.js to webpack.config.development.js. Then make a copy and name it webpack.config.production.js.

将Webpack配置从webpack.config.js重命名为webpack.config. development .js webpack.config. development .js 。 然后制作一个副本并将其命名为webpack.config.production.js

In your terminal type the following:

在终端中输入以下内容:

mv webpack.config.js webpack.config.development.js
cp webpack.config.development.js webpack.config.production.js

We will need a development dependency, Extract Text Plugin. From their docs: “It moves all the required *.css modules in entry chunks into a separate CSS file. So, your styles are no longer inlined into the JS bundle, but in a separate CSS file (styles.css). If your total stylesheet volume is big, it will be faster because the CSS bundle is loaded in parallel to the JS bundle.”

我们将需要一个开发依赖项Extract Text Plugin 。 在他们的文档中:“它将条目块中所有必需的*.css模块移动到单独CSS文件中。 因此,您的样式不再内联到JS包中,而是在一个单独CSS文件( styles.css )中。 如果您的样式表总容量很大,那么速度会更快,因为CSS包与JS包并行加载。”

In your terminal type the following:

在终端中输入以下内容:

yarn add mini-css-extract-plugin -D

Open webpack.config.production.js and make the following bolded changes:

打开webpack.config.production.js并进行以下粗体更改:

Doing something different here…I will add explanations with inline comments.

在这里做一些不同的事情…我将在解释中添加内嵌注释。

const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {mode: 'production',entry: {vendor: ['semantic-ui-react'],app: './src/index.js'},output: {// We want to create the JavaScript bundles under a // 'static' directoryfilename: 'static/[name].[hash].js',// Absolute path to the desired output directory. In our //case a directory named 'dist'// '__dirname' is a Node variable that gives us the absolute// path to our current directory. Then with 'path.resolve' we // join directories// Webpack 4 assumes your output path will be './dist' so you // can just leave this// entry out.path: path.resolve(__dirname, 'dist'),publicPath: '/'},// Change to production source mapsdevtool: 'source-map',module: {rules: [{test: /\.(js)$/,exclude: /node_modules/,use: ['babel-loader']},{test: /\.css$/,use: [{// We configure 'MiniCssExtractPlugin'              loader: MiniCssExtractPlugin.loader,}, {loader: 'css-loader',options: {modules: true,// Allows to configure how many loaders // before css-loader should be applied// to @import(ed) resourcesimportLoaders: 1,localsConvention: 'camelCase',// Create source maps for CSS filessourceMap: true}},{// PostCSS will run before css-loader and will // minify and autoprefix our CSS rules.loader: 'postcss-loader',}]}]},optimization: {splitChunks: {cacheGroups: {styles: {name: 'styles',test: /\.css$/,chunks: 'all',enforce: true},vendor: {chunks: 'initial',test: 'vendor',name: 'vendor',enforce: true}}}},plugins: [new HtmlWebpackPlugin({template: 'public/index.html',favicon: 'public/favicon.ico'}),// Create the stylesheet under 'styles' directorynew MiniCssExtractPlugin({filename: 'styles/styles.[hash].css'})]
};

Notice we removed the port variable, the plugins related to HMR and the devServer entry.

注意,我们删除了port变量,与HMR相关的插件和devServer条目。

Also since we added PostCSS to the production configuration, we need to install it and create a configuration file for it.

另外,由于我们将PostCSS添加到生产配置中,因此我们需要安装它并为其创建配置文件。

In your terminal type the following:

在终端中输入以下内容:

yarn add postcss-loader autoprefixer cssnano postcss-preset-env -D
touch postcss.config.js

Open postcss.config.js and copy the following:

打开postcss.config.js并复制以下内容:

const postcssPresetEnv = require('postcss-preset-env');
module.exports = {plugins: [postcssPresetEnv({browsers: ['>0.25%', 'not ie 11', 'not op_mini all']}),require('cssnano')]
};

Here we are specifying what browsers we want autoprefixer (Refer to the Docs for more options) to support and minifying the CSS output.

在这里,我们指定了我们希望自动autoprefixer浏览器(有关更多选项,请参阅文档 ),并最小化CSS输出。

Now for the last step before we create our production build, we need to create a build script in package.json.

现在,在创建生产构建之前的最后一步,我们需要在package.json创建一个构建脚本。

Open the file and make the following changes to the scripts section:

打开文件,并对scripts部分进行以下更改:

...
"scripts": {"dev":"webpack-dev-server --config webpack.config.development.js","prebuild": "rimraf dist","build": "cross-env NODE_ENV=production webpack -p --config webpack.config.production.js"
},
...

First thing to notice here is that we changed the start script from start to dev, then we added two additional scripts, prebuild and build.

首先要注意的是,我们将启动脚本从start更改为dev ,然后添加了两个附加脚本prebuildbuild

Finally, we are indicating which configuration to use when in development or production.

最后,我们指出了在开发或生产中使用哪种配置。

  • prebuild — Will run before the build script and delete the dist directory created by our last production build. We use the library rimraf for this

    prebuild —将在构建脚本之前运行,并删除我们上次生产构建所创建的dist目录。 我们为此使用rimraf库

  • build — First we use cross-env library just in case somebody is using Windows. This way setting up environment variables with NODE_ENV will work. Then we call Webpack with the -p flag to tell it to optimize this build for production, and finally we specify the production configuration.

    build —首先,我们使用cross-env库,以防万一有人使用Windows。 这样可以使用NODE_ENV设置环境变量。 然后,我们使用-p标志调用Webpack,以告知它为生产优化此构建,最后指定生产配置。

In your terminal install the two new dependencies we included in package.json:

在您的终端中,安装package.json包含的两个新依赖项:

yarn add rimraf cross-env -D

Before creating the production build, let us look at our new project structure:

在创建生产版本之前,让我们看一下新的项目结构:

|-- node_modules
|-- public|-- index.html|-- favicon.ico
|-- src|-- components|-- App.js|-- DynamicPage.js|-- Home.js|-- Layout.css|-- Layout.js|-- Loading.js|-- NoMatch.js|-- index.js
|-- .babelrc
|-- package.json
|-- postcss.config.js
|-- webpack.config.development.js
|-- webpack.config.production.js
|-- yarn.lock

At last we can create our production bundle.

最后,我们可以创建我们的生产捆绑包。

In your terminal type the following:

在终端中输入以下内容:

yarn build

As you noticed, after we ran the build script, Webpack created a dist directory containing our production ready app. Now inspect the files that were created and notice they are minified and each has a corresponding source map. You will also notice PostCSS has added autoprefixing to the CSS file.

正如您所注意到的,在运行build脚本后,Webpack创建了一个包含生产就绪应用程序的dist目录。 现在检查创建的文件,并注意将它们缩小,每个文件都有对应的源映射。 您还将注意到PostCSS已将自动前缀添加到CSS文件。

Now we take our production files and fire up a Node server to serve our site, and this is the result:

现在,我们获取生产文件并启动节点服务器来为我们的站点提供服务,结果如下:

Note: I am using this server in the GIF above to serve our production files.

注意: 我在上面的GIF中使用此服务器来提供我们的生产文件。

At this point we have two working Webpack configurations, one for development and one for production. However, since both configurations are very similar, they share many of the same settings. If we wanted to add something else, we would have to add it to both configurations files. Let’s fix this inconvenience.

至此,我们有两种有效的Webpack配置,一种用于开发,另一种用于生产。 但是,由于两种配置非常相似,因此它们共享许多相同的设置。 如果要添加其他内容,则必须将其添加到两个配置文件中。 让我们解决此不便之处。

Webpack组成 (Webpack Composition)

Let’s start by installing webpack-merge and Chalk as development dependencies.

让我们首先安装webpack-merge和Chalk作为开发依赖项。

In your terminal type the following:

在终端中输入以下内容:

yarn add webpack-merge chalk -D

We will also need a couple of new directories and a few new files.

我们还将需要几个新目录和一些新文件。

In your terminal type the following:

在终端中输入以下内容:

mkdir -p build-utils/addons
cd build-utils
touch build-validations.js common-paths.js webpack.common.js webpack.dev.js webpack.prod.js

Now let’s look at our new project structure:

现在让我们看一下我们的新项目结构:

|-- build-utils|-- addons|-- build-validations.js|-- common-paths.js|-- webpack.common.js|-- webpack.dev.js|-- webpack.prod.js
|-- node_modules
|-- public|-- index.html|-- favicon.ico
|-- src|-- components|-- App.js|-- DynamicPage.js|-- Home.js|-- Layout.css|-- Layout.js|-- Loading.js|-- NoMatch.js|-- index.js
|-- .babelrc
|-- package.json
|-- postcss.config.js
|-- webpack.config.development.js
|-- webpack.config.production.js
|-- yarn.lock

Open common-paths.js and copy the following:

打开common-paths.js并复制以下内容:

const path = require('path');
const PROJECT_ROOT = path.resolve(__dirname, '../');module.exports = {projectRoot: PROJECT_ROOT,outputPath: path.join(PROJECT_ROOT, 'dist'),appEntry: path.join(PROJECT_ROOT, 'src')
};

Here we define, as the name implies, the common paths for our Webpack configurations. PROJECT_ROOT needs to look one directory up as we are working under build-utils directory (one level down from the actual root path in our project).

顾名思义,这里我们定义了Webpack配置的公共路径。 当我们在build-utils目录下工作时, PROJECT_ROOT需要向上查找一个目录(比项目中实际的根路径低一级)。

Open build-validations.js and copy the following:

打开build-validations.js并复制以下内容:

const chalk = require('chalk');
const ERR_NO_ENV_FLAG = chalk.red(`You must pass an --env.env flag into your build for webpack to work!`
);module.exports = {ERR_NO_ENV_FLAG
};

Later when we modify our package.json we will be requiring –env.env flag in the scripts. These validations are to verify that the flag is present; if not, it will throw an error.

稍后,当我们修改package.json我们将在脚本中要求使用–env.env标志。 这些验证是为了验证该标志是否存在。 如果没有,它将抛出错误。

In the next three files, we will be separating the Webpack configurations into configurations that are shared among development and production, configurations that are only for development and configurations only for production.

在接下来的三个文件中,我们将把Webpack配置分为开发和生产中共享的配置,仅用于开发的配置和仅用于生产的配置。

Open webpack.common.js and copy the following:

打开webpack.common.js并复制以下内容:

const commonPaths = require('./common-paths');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const config = {entry: {vendor: ['semantic-ui-react']},output: {path: commonPaths.outputPath,publicPath: '/'},module: {rules: [{test: /\.(js)$/,exclude: /node_modules/,use: ['babel-loader']}]},optimization: {splitChunks: {cacheGroups: {styles: {name: 'styles',test: /\.css$/,chunks: 'all',enforce: true},vendor: {chunks: 'initial',test: 'vendor',name: 'vendor',enforce: true}}}},plugins: [new HtmlWebpackPlugin({template: 'public/index.html',favicon: 'public/favicon.ico'})]
};
module.exports = config;

We basically extracted out what was shared among webpack.config.development.js and webpack.config.production.js and transferred it to this file. At the top we require common-paths.js to set the output.path.

我们基本上提取了webpack.config.development.jswebpack.config.production.js之间共享的webpack.config.development.js ,并将其传输到此文件中。 在顶部,我们需要common-paths.js来设置output.path

Open webpack.dev.js and copy the following:

打开webpack.dev.js并复制以下内容:

const commonPaths = require('./common-paths');
const webpack = require('webpack');
const port = process.env.PORT || 3000;
const config = {mode: 'development',entry: {app: `${commonPaths.appEntry}/index.js`},output: {filename: '[name].[hash].js'},resolve: {alias: {"react-dom": "@hot-loader/react-dom",},},devtool: 'inline-source-map',module: {rules: [{test: /\.css$/,use: [{loader: 'style-loader'},{loader: 'css-loader',options: {modules: true,localsConvention: 'camelCase',sourceMap: true}}]}]},plugins: [new webpack.HotModuleReplacementPlugin()],devServer: {host: 'localhost',port: port,historyApiFallback: true,hot: true,open: true}
};
module.exports = config;

This is the same concept as with the previous file. Here we extracted out development only configurations.

这与上一个文件的概念相同。 在这里,我们提取了仅开发配置。

Open webpack.prod.js and copy the following:

打开webpack.prod.js并复制以下内容:

const commonPaths = require('./common-paths');
const webpack = require('webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const config = {mode: 'production',entry: {app: [`${commonPaths.appEntry}/index.js`]},output: {filename: 'static/[name].[hash].js'},devtool: 'source-map',module: {rules: [{test: /\.css$/,use: [{// We configure 'MiniCssExtractPlugin'              loader: MiniCssExtractPlugin.loader,}, {loader: 'css-loader',options: {modules: true,importLoaders: 1,localsConvention: 'camelCase',sourceMap: true}},{loader: 'postcss-loader'}]}]},plugins: [new MiniCssExtractPlugin({filename: 'styles/styles.[hash].css'})]
};
module.exports = config;

We extracted out production only configurations.

我们提取了仅生产配置。

Now that we have the shared configurations and the ones specific for development and production in separate files, it is time to put everything together.

现在我们有了共享的配置,以及专门用于开发和生产的配置在单独的文件中,是时候将所有内容放在一起了。

In terminal, if you are still in build-utils directory, go up one level to the root of the project, then delete the previous Webpack configurations and create a new Webpack configuration. Name it webpack.config.js.

在终端中,如果您仍在build-utils目录中,请向上一级到项目的根目录,然后删除以前的Webpack配置并创建一个新的Webpack配置。 将其命名为webpack.config.js

In your terminal type the following:

在终端中输入以下内容:

cd ..
rm webpack.config.development.js webpack.config.production.js
touch webpack.config.js

Before configuring webpack.config.js, let’s open package.json and update the scripts section.

在配置webpack.config.js之前,让我们打开package.json并更新scripts部分。

Modify the section as follows:

修改部分,如下所示:

...
"scripts": {"dev": "webpack-dev-server --env.env=dev","prebuild": "rimraf dist","build": "cross-env NODE_ENV=production webpack -p --env.env=prod"
},
...

Since we removed the –config flag, Webpack will now be looking for the default configuration, which is webpack.config.js. Now we use the –env flag to pass an environment variable to Webpack, env=dev for development and env=prod for production.

由于我们删除了–config标志,因此Webpack现在将寻找默认配置,即webpack.config.js 。 现在,我们使用–env标志将环境变量传递给Webpack, env=dev用于开发, env=prod用于生产。

Open webpack.config.js and copy the following:

打开webpack.config.js并复制以下内容:

Explanations with inline comments.

内嵌注释的说明。

const buildValidations = require('./build-utils/build-validations');
const commonConfig = require('./build-utils/webpack.common');const webpackMerge = require('webpack-merge');// We can include Webpack plugins, through addons, that do 
// not need to run every time we are developing.
// We will see an example when we set up 'Bundle Analyzer'
const addons = (/* string | string[] */ addonsArg) => {// Normalize array of addons (flatten)let addons = [...[addonsArg]] .filter(Boolean); // If addons is undefined, filter it outreturn addons.map(addonName =>require(`./build-utils/addons/webpack.${addonName}.js`));
};// 'env' will contain the environment variable from 'scripts' 
// section in 'package.json'.
// console.log(env); => { env: 'dev' }
module.exports = env => {// We use 'buildValidations' to check for the 'env' flagif (!env) {throw new Error(buildValidations.ERR_NO_ENV_FLAG);}// Select which Webpack configuration to use; development // or production// console.log(env.env); => devconst envConfig = require(`./build-utils/webpack.${env.env}.js`);// 'webpack-merge' will combine our shared configurations, the // environment specific configurations and any addons we are// includingconst mergedConfig = webpackMerge(commonConfig,envConfig,...addons(env.addons));// Then return the final configuration for Webpackreturn mergedConfig;
};

Now, this might seem like a lot of setup, but in the long run, it will come in handy.

现在,这似乎是很多设置,但从长远来看,它将派上用场。

At this time, you can launch the application or build the production files, and everything will function as expected (sorry, no GIF this time).

这时,您可以启动应用程序或生成生产文件,一切将按预期运行(对不起,这次没有GIF)。

yarn dev
yarn build

Note: This “Webpack Composition” technique was taken from Webpack Academy, a free course by Sean Larkin which I recommend taking to learn more about Webpack, not specific to React.

注意: 这种“ Webpack合成”技术来自Webpack学院 ,这是Sean Larkin的免费课程,我建议您学习更多有关Webpack的知识,而不是专门针对React。

奖励:设置Webpack Bundle Analyzer (BONUS: Setting up Webpack Bundle Analyzer)

You don’t necessarily need Webpack Bundle Analyzer, but it does comes in handy when trying to optimize your builds.

您不一定需要Webpack Bundle Analyzer ,但在尝试优化构建时确实很方便。

Start by installing the dependency and creating the configuration file.

首先安装依赖项并创建配置文件。

In your terminal type the following:

在终端中输入以下内容:

yarn add webpack-bundle-analyzer -D
touch build-utils/addons/webpack.bundleanalyzer.js

Open webpack.bundleanalyzer.js and copy the following:

打开webpack.bundleanalyzer.js并复制以下内容:

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;module.exports = {plugins: [new BundleAnalyzerPlugin({analyzerMode: 'server'})]
};

We are just exporting the plugins section, which includes Bundle Analyzer, for Webpack. Then webpack-merge will combine it into the final Webpack configuration. Remember the addons in webpack.config.js? Well, this is where it comes into place.

我们仅导出Webpack的插件部分,其中包括Bundle Analyzer。 然后, webpack-merge将其webpack-merge到最终的Webpack配置中。 还记得webpack.config.js插件吗? 好吧,这就是它的地方。

For the final step, let’s open package.json and include the new scripts as follows:

对于最后一步,我们打开package.json并包括如下新脚本:

"scripts": {"dev": "webpack-dev-server --env.env=dev","dev:bundleanalyzer": "yarn dev --env.addons=bundleanalyzer","prebuild": "rimraf dist","build": "cross-env NODE_ENV=production webpack -p --env.env=prod","build:bundleanalyzer": "yarn build --env.addons=bundleanalyzer"
},
  • dev:bundleanalyzer — Calls the dev script and passes a new environment variable addons=bundleanalyzer

    dev:bundleanalyzer —调用dev脚本并传递新的环境变量addons=bundleanalyzer

  • build:bundleanalyzer — Calls the build script and passes a new environment variable addons=bundleanalyzer

    build:bundleanalyzer —调用build脚本并传递新的环境变量addons=bundleanalyzer

Time to run the app with the bundle analyzer addon.

是时候使用捆绑分析器插件运行该应用程序了。

In your terminal type the following:

在终端中输入以下内容:

yarn dev:bundleanalyzer

The application launches alongside Webpack Bundle Analyzer.

该应用程序与Webpack Bundle Analyzer一起启动。

Including addons with Webpack Composition can be very useful, as there are many plugins that you would want to use only at certain times.

包含带有Webpack Composition的插件可能非常有用,因为有很多插件您只想在特定时间使用。

结论 (Conclusion)

First of all, you can get the full code on the GitHub repository.

首先,您可以在GitHub存储库中获取完整的代码。

Well, you made it to the end. Congratulations!! ? Now that you know the basics (and a little more) of Webpack for React, you can go ahead and keep exploring and learning more advanced features and techniques.

好吧,你做到了最后。 恭喜!! ? 既然您已经了解了Webpack for React的基础知识(以及更多知识),那么您就可以继续探索并学习更多高级功能和技术。

Thank you for reading and I hope you enjoyed it. If you have any questions, suggestions or corrections let me know in the comments below. Don’t forget to give this article a Share and some Claps ??.

感谢您的阅读,希望您喜欢它。 如果您有任何疑问,建议或更正,请在下面的评论中告诉我。 不要忘了给这篇文章一个“分享”和一些“鼓掌”。

You can follow me here on Medium, Twitter, GitHub, LinkedIn or all of them.

您可以在Medium , Twitter , GitHub , LinkedIn或所有这些站点上关注我。

This article was originally published on my personal blog website.

本文最初发布在我的个人博客网站上 。



Update 8/25/19: I have been building a prayer web app called "My Quiet Time - A Prayer Journal". If you would like to stay in the loop please sign up through the following link: http://b.link/mqt  

19年8月25日更新:我一直在构建一个祷告网络应用程序,名为“ 我的安静时间-祷告日记 ”。 如果您想停留在循环中,请通过以下链接进行注册: http : //b.link/mqt

The app will be released before the end of the year, I have big plans for this app. To see some mockup screenshots follow the following link: http://pc.cd/Lpy7

该应用程序将在今年年底之前发布,我对此应用程序有很大的计划。 要查看一些模型截图,请点击以下链接: http : //pc.cd/Lpy7

My DMs on Twitter are open if you have any questions regarding the app 😄

如果您对应用程序有任何疑问,我在Twitter上的 DM处于打开状态😄

翻译自: https://www.freecodecamp.org/news/learn-webpack-for-react-a36d4cac5060/

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/4/7737.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息