vortesnail / blog

:blue_book: 个人技术小文章,旨在对知识的总结,能帮助到别人就更好啦。
551 stars 45 forks source link

从零配置webpack 4+react脚手架(一) #4

Open vortesnail opened 5 years ago

vortesnail commented 5 years ago

从零配置webpack 4+react脚手架(一)

前言:

如果你和我一样学习了webpack相关的教程,并跟着webpack官方指南进行了一些简单的配置,但是不知道如何去使用它,那么这个系列的文章将通过搭建webpack+react脚手架给予你一定的配置经验,写这个系列的文章一是为了方便以后自己有配置需求时可以及时回顾,二是加强自己对于webpack的理解。我会尽可能详细地一步一步讲解这个脚手架配置步骤,也会对一些需要注意的点进行提醒,希望能帮助到大家~

前提:

开始吧!

建一个空文件夹

让我们在桌面建一个空文件夹,名为 webpck-react-scaffold ,并使用你的编辑器打开它。
将此文件夹拖到终端,执行:

npm init -y

上面命令会在你的根目录生成 package.json 文件,该文件定义了这个项目所需要的各种模块,以及项目的配置信息(比如名称、版本、许可证等元数据)。npm install命令根据这个配置文件,自动下载所需的模块,也就是配置项目所需的运行和开发环境。

安装webpack

因为我们使用的是 webpack 4+ 版本,还需要安装 webpack-cli ,执行以下命令:

npm install --save-dev webpack webpack-cli

安装完成,你会发现在 package.josn 中多了一个 devDependencies 属性,这是因为我们安装依赖包时 --save-dev 的结果,这代表了开发时的依赖。之后我们会只用 --save 安装依赖包,这代表了运行时依赖。

我们确认一下,现在根目录下的文件结构如下:

  webpack-react-scaffold
  |- node_modules
  |- package.json

接下来,我们在根目录下新建一个文件夹名为 config 用于存放配置文件,在此文件夹下创建一个 .js 文件名为 webpack.common.config.js ,敲入以下代码:

const path = require('path');

module.exports = {
  entry: {
    app: './src/app.js',
  },
  output: {
    filename: 'js/bundle.js',
    path: path.resolve(__dirname, '../dist')
  }
}

webpack 配置是标准的 Node.js的CommonJS 模块,它通过require来引入其他模块,通过module.exports导出模块,由 webpack 根据对象定义的属性进行解析。

entry 属性定义了入口文件路径, output 定义了编译打包之后的文件名以及所在路径。
这段代码的意思是告诉webpack,入口文件是 src 目录下的 app.js 文件。打包输出的文件名字为 bundle.js ,保存在上一级目录下的 dist 文件夹中。 

我们创建一个文件夹名为 src ,在其中新建一个js文件名为 app.js ,现在我们的目录结构如下:

  webpack-react-scaffold
+ |- config
+     |- webpack.common.config.js
  |- node_modules
+ |- src
+     |- app.js
  |- package.json

那我们怎么打包呢?在 package.json 中配置如下属性:

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
+  "start": "webpack --config ./config/webpack.common.config.js"
  },

好了,我们试试怎么打包吧,虽然你的 app.js 中什么代码也没有。
在控制台中输入以下代码:

npm run start

想必你也看出来了,为什么是 “start”,--config选项来指定配置文件。
执行之后,你会发现根目录多出了一个文件夹: dist/js ,其中有一个js文件: bundle.js ,那么至此,我们已经成功编译打包了一个js文件,即入口文件: app.js 。

使用webpack-merge

我们将使用一个名为 webpack-merge 的工具。通过“通用”配置,我们不必在环境特定(environment-specific)的配置中重复代码。简单来说就是生产环境不同,我们要给的配置也有所不同,但是可以共用一个共有的配置。

我们先从安装 webpack-merge 开始:

npm install --save-dev webpack-merge

安装结束之后,我们在 config 这个文件夹下新建两个文件,分别为 webpack.prod.config.js 和 webpack.dev.config.js ,这两个文件分别对应生产和开发两个环境的配置。

现在的目录结构:

  webpack-react-scaffold
  |- config
     |- webpack.common.config.js
+    |- webpack.prod.config.js
+    |- webpack.dev.config.js
  |- node_modules
  |- src
     |- app.js
  |- package.json

webpack.prod.config.js 中输入以下代码:

const merge = require('webpack-merge');
const common = require('./webpack.common.config.js');

module.exports = merge(common, {
  mode: 'production',
});

回到我们之前创建的 app.js 文件,输入代码:

var root =document.getElementById('root');
root.innerHTML = 'hello, webpack!';

在根目录下创建一个文件夹名为: public ,再新建一个html文件,名为: 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">
  <title>从零配置webpack4+react脚手架</title>
</head>
<body>
  <div id="root"></div>
  <script src="../dist/js/bundle.js"></script>
</body>
</html>

现在的目录结构是这样子(只要不编译打包,要引入的 bundle.js 就没有):

  webpack-react-scaffold
   |- config
      |- webpack.common.config.js
      |- webpack.prod.config.js
      |- webpack.dev.config.js
   |- node_modules
+  |- public
+     |- index.html
   |- src
      |- app.js
   |- package.json

打包之前,我们修改 package.json :

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
-   "start": "webpack --config ./config/webpack.common.config.js",
+   "build": "webpack --config ./config/webpack.prod.config.js"
  },

好了,接下来我们编译打包试试吧!控制台执行以下代码:

npm run build

我们可以看到,webpack重新进行了编译,这和执行
webpack --config config/webpack.prod.conf.js 是一样的效果。
现在你可以打开用浏览器 public/index.html ,看看是不是有东西了~~

安装React

在控制台输入以下代码:

npm install --save react react-dom

安装完成之后,我们就可以写react的JSX语法了。

这里为了和react官方脚手架 create-react-app 的目录结构相类似,我们在 src 文件夹下新建一个js文件, index.js ,用于渲染根组件。

index.js 输入以下代码:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));

并用jsx语法重写 app.js :

import React from 'react';

function App() {
  return (
    <div className="App">Hello World</div>
  );
}

export default App;

webpack.common.config.js 文件中的入口进行修改,因为我们现在要编译打包的应该 index.js :

  const path = require('path');

  module.exports = {
    entry: {
-     app: './src/app.js',
+     index: './src/index.js',
    },
    output: {
      filename: 'js/bundle.js',
      path: path.resolve(__dirname, '../dist')
    }
  }

现在尝试一下重新运行 npm run build ,会发现打包失败了,为什么呢?接着看.....

使用babel 7

为什么我们上面写jsx会打包不了呢,因为webpack根本识别不了jsx语法,那怎么办?使用loader对文件进行预处理。
其中,babel-loader,就是这样一个预处理插件,它加载 ES2015+ 代码,然后使用 Babel 转译为 ES5。那开始配置它吧!

首先安装babel相关的模块:

npm install --save-dev babel-loader @babel/preset-react @babel/preset-env @babel/core

理论上我们可以直接在 webpack.common.config.js 中配置"options",但最好在当前根目录,注意,一定要是根目录!!! 新建一个配置文件 .babelrc 配置相关的"presets":

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          // 大于相关浏览器版本无需用到 preset-env
          "edge": 17,
          "firefox": 60,
          "chrome": 67,
          "safari": 11.1
        },
        // 根据代码逻辑中用到的 ES6+语法进行方法的导入,而不是全部导入
        "useBuiltIns": "usage"
      }
    ],
    "@babel/preset-react"
  ]
}

这里有关bebel的配置可上官网查询文档。

再修改 webpack.common.config.js ,添加如下代码:

const path = require('path');

module.exports = {
  entry: {
    index: './src/index.js',
  },
  output: {
    filename: 'js/bundle.js',
    path: path.resolve(__dirname, '../dist')
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        use: 'babel-loader',
        exclude: /node_modules/,
      }
    ]
  }
}

test 规定了作用于以规则中匹配到的后缀结尾的文件, use 即是使用 babel-loader 必须的属性, exclude 告诉我们不需要去转译"node_modules"这里面的文件。

接下来:

npm run build

是不是能打包成功了呢?回到你的html页面,看一下是否打印出了“hello webpack”吧!

我们再最后确认一下我们的目录:

  webpack-react-scaffold
   |- config
      |- webpack.common.config.js
      |- webpack.prod.config.js
      |- webpack.dev.config.js
   |- node_modules
   |- public
      |- index.html
   |- src
+     |- index.js
      |- app.js
+  |- .babelrc
   |- package.json

这一小节就到这里,你会发现有很多功能还是没有得以实现,比如自动生成html文件,实时刷新页面等,下一节开始我们会逐步优化我们的配置!

LaughSun0513 commented 4 years ago

哈哈哈,你的行文风格我很喜欢

vortesnail commented 4 years ago

哈哈哈,你的行文风格我很喜欢

受到了鼓励,表示相当高兴啊

MJC237 commented 4 years ago

非常感谢,比他其他文章简单易理解,对于我这个笨蛋而言哈哈哈

fsa2000 commented 4 years ago

非常感谢!!!写的很细仔,后台开发人员能够理解不容易!!!

luzh0422 commented 4 years ago

真的写的很棒,条理清晰,好文。

Lisianthus-A commented 4 years ago

使用merge后npm run start提示merge is not function. merge那行换成这个就行了

const { merge } = require('webpack-merge');
licoded commented 3 years ago

哈哈哈,你的行文风格我很喜欢

我也是

hover-chuanzi025 commented 1 year ago

可以可以,非常好,对我帮助很大,哈哈