Webpack從零配置React的運行環境上篇——搭建基本環境

以前一直用官方的腳手架來建立react應用,用eject指令後查看weback的一些配置後發現就是基於webpack的多層優化,但裏面用到的東西太多也比較雜,每次都不知道本身的react應用到底用了哪些技術棧,因此打算本身從零搭建一個相似於官方的腳手架,方便個性化處理

項目的地址

https://github.com/jianjiache...
內部配置大部分作了詳細說明
執行方式:
cnpm install
cnpm run start
cnpm run buildcss

完成的功能

  • [x] 分離生產環境與開發環境
  • [x] 添加source-map方便調試
  • [x] 分析了babel-polyfill不一樣導入方式的影響
  • [x] 代碼分割 定義了被抽離的模塊如何分紅組
  • [x] 識別React語法以及ES6
  • [x] 處理了不兼容ES7修飾器(@)Decorator的問題
  • [x] 加入了less以及sass的處理
  • [x] 抽離了全部的css樣式文件
  • [x] 壓縮了JS代碼以及CSS代碼
  • [x] 添加了CSS自動補全瀏覽器前綴,加強了適配性
  • [x] 完成對字體、圖片、媒體文件的按大小分類打包策略
  • [x] 生成一個HTML文件,並主動加入JS文件
  • [x] 配置刪除生產環境的console.log
  • [x] 每次打包先清除dist目錄
  • [x] 加入了代碼的熱更新,修改代碼自動編譯
  • [x] 加入了webpack多入口的配置
  • [x] 加入了對包大小的可視化分析工具

初始化package.json

建立一個WebpackReact項目,使用cnpm init -y指令
-y: 避免一直確認輸入yeshtml

安裝 webpack 和 webpack-cli 到開發環境

npm install --save-dev webpack webpack-clinode

建立一個公共打包的配置

建立一個公共打包的配置文件名爲 webpack.common.config.jsreact

WebpackReact
├── config
│   ├── 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')
  }
}

建立一個文件夾名爲 src ,在其中新建一個js文件名爲 app.js

寫入console.log('hello world')webpack

WebpackReact
├── src
│   ├── app.js

修改package.json指令

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

初次打包

npm run start
在dist/js ,其中有一個js文件: bundle.jsgit

!(function(e) {
  var t = {};
  function n(r) {
    if (t[r]) return t[r].exports;
    var o = (t[r] = { i: r, l: !1, exports: {} });
    return e[r].call(o.exports, o, o.exports, n), (o.l = !0), o.exports;
  }
  (n.m = e),
    (n.c = t),
    (n.d = function(e, t, r) {
      n.o(e, t) || Object.defineProperty(e, t, { enumerable: !0, get: r });
    }),
    (n.r = function(e) {
      "undefined" != typeof Symbol &&
        Symbol.toStringTag &&
        Object.defineProperty(e, Symbol.toStringTag, { value: "Module" }),
        Object.defineProperty(e, "__esModule", { value: !0 });
    }),
    (n.t = function(e, t) {
      if ((1 & t && (e = n(e)), 8 & t)) return e;
      if (4 & t && "object" == typeof e && e && e.__esModule) return e;
      var r = Object.create(null);
      if (
        (n.r(r),
        Object.defineProperty(r, "default", { enumerable: !0, value: e }),
        2 & t && "string" != typeof e)
      )
        for (var o in e)
          n.d(
            r,
            o,
            function(t) {
              return e[t];
            }.bind(null, o)
          );
      return r;
    }),
    (n.n = function(e) {
      var t =
        e && e.__esModule
          ? function() {
              return e.default;
            }
          : function() {
              return e;
            };
      return n.d(t, "a", t), t;
    }),
    (n.o = function(e, t) {
      return Object.prototype.hasOwnProperty.call(e, t);
    }),
    (n.p = ""),
    n((n.s = 0));
})([
  function(e, t) {
    console.log('hello world');// 在這裏能夠看到咱們的代碼
  }
]);

區分生產環境和開發環境

咱們須要一個公共的配置,而後基於這個公共的配置上,生成生產環境的配置和開發環境的配置github

npm install --save-dev webpack-mergeweb

WebpackReact-----------------------------------根目錄
├── config
│   ├── webpack.common.config.js---------------公共的配置
│   ├── webpack.dev.config.js------------------生產環境的配置
│   └── webpack.prod.config.js-----------------開發環境的配置

在生產環境webpack.prod.config.js就能夠這樣使用mergechrome

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

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

而後修改package.json文件,添加指令npm

"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"
  },

修改app.js代碼:

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

運行代碼npm run build就能夠看到dist文件下打包的js

測試打包結果

咱們建立一個public來測試打包運行的結果,後面會用插件來幹這件事

WebpackReact
├── config
│   ├── webpack.common.config.js
│   ├── webpack.dev.config.js
│   └── webpack.prod.config.js
├── dist
├── package.json
├── public
│   └── index.html ------------------建立來測試打包的JS是否可用
├── readme.md
├── src
│   ├── app.js

public裏建立一個html並引入打包好的JS文件

<!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>

直接在瀏覽器裏運行這個文件

安裝react

npm install --save react react-dom

在 src 文件夾下新建一個js文件, index.js ,用於渲染根組件。

WebpackReact
├── config
│   ├── webpack.common.config.js
│   ├── webpack.dev.config.js
│   └── webpack.prod.config.js
├── dist
├── package.json
├── public
│   └── index.html ------------------建立來測試打包的JS是否可用
├── readme.md
├── src
│   ├── app.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入口文件配置

const path = require('path');

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

直接從新運行npm run build ,會發現打包失敗,緣由是webpack沒法識別你的react語法啊,須要預先編譯

配置bable

安裝相關的bable依賴

npm install --save-dev babel-loader @babel/preset-react @babel/preset-env @babel/core
  • babel-loader:使用Babel和webpack來轉譯JavaScript文件。
  • @babel/preset-react:轉譯react的JSX
  • @babel/preset-env:轉譯ES2015+的語法
  • @babel/core:babel的核心模塊

根目錄新建一個配置文件.babelrc 配置相關的"presets"

{
    "presets": [// presets 就是 plugins 的組合
      [
        "@babel/preset-env",
        {
          "targets": {
            // 大於相關瀏覽器版本無需用到 preset-env
            "edge": 17,
            "firefox": 60,
            "chrome": 67,
            "safari": 11.1
          },
          // 根據代碼邏輯中用到的 ES6+語法進行方法的導入,而不是所有導入
          "useBuiltIns": "usage" //useBuiltIns就是是否開啓自動支持 polyfill,它能自動給每一個文件添加其須要的poly-fill。
        }
      ],
      "@babel/preset-react"
    ],
    "plugins": [
      ["@babel/plugin-proposal-decorators", { "legacy": true }]// 轉義ES7的修飾器@
    ]
  }

再修改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/,//不須要去轉譯"node\_modules"這裏面的文件。
      }
    ]
  }
}

如今從新打包應該能成功了,別且運行咱們手動建立的HTML文件能看到一個hello world

自動編譯html並引入js文件

html-webpack-plugin

html-webpack-plugin用來生成HTML文件自動引用打包好的JS文件

npm install --save-dev html-webpack-plugin
const merge = require('webpack-merge');
const common = require('./webpack.common.config.js');

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

module.exports = merge(common, {
  mode: 'production',
  plugins: [
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'public/index.html',// 定義的html爲模板生成 從根路徑開始查找
      inject: 'body',
      minify: {// 壓縮HTML文件
        removeComments: true,//去除註釋
        collapseWhitespace: true,//去除空格
      },
    }),
  ]
});

CSS跑起來

在咱們的/src 目錄下,新建一個文件名爲app.css ,並輸入如下代碼:

.App {
  height: 200px;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: lightcoral;
}

h1 {
  font-size: 16px;
  color: #fff;
}

在app.js中引入css

import  './app.css';

配置loader
wbpack只能編譯js文件,css文件是沒法被識別並編譯的,咱們須要loader加載器來進行預處理。 首先安裝style-loader 和css-loader :

npm install --save-dev style-loader css-loader

在module的rules裏添加配置

{
        test: /\.css$/,
        use: [ 
           
          'style-loader',// 最後計算完的css,將會使用style-loader生成一個內容爲最終解析完的css代碼的style標籤,放到head標籤裏
          'css-loader' // css-loader加載器去解析這個文件,遇到「@import」等語句就將相應樣式文件引入
        ]
      }

能夠看到CSS已經內嵌到了咱們頁面,咱們能夠優化一下讓它單獨提出來,下一章會詳細說明

注意

css編譯器順序可能會致使了Webpack編譯報錯

Webpack選擇了compose方式,而不是pipe的方式而已,從右往左的函數式,因此loader的順序編程了從右往左

const compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x);
const add1 = n => n + 1; //加1
const double = n => n * 2; // 乘2
const add1ThenDouble = compose(
  double,
  add1
);
add1ThenDouble(2); // 6
// ((2 + 1 = 3) * 2 = 6)

由於執行順序必須是(先用加載器解析,再最終解析到style標籤)css-loader->style-loader->
因此style-loader放在css-loader的左邊,也就是上面

如今的目錄結構

WebpackReact
├── config
│   ├── webpack.common.config.js ------------------------公共的配置
│   ├── webpack.dev.config.js ---------------------------開發環境配置(還未配置)
│   └── webpack.prod.config.js -------------------------生產環境配置
├── dist -----------------------------------------------打包的文件
├── package.json ---------------------------------------配置文件
├── public 
│   └── index.html -------------------------------------手動建立的入口後面會用插件打入包裏
├── readme.md ------------------------------------------說明文檔
├── src
│   ├── app.js ----------------------------------------組件
│   ├── app.css --------------------------------------樣式文件
│   └── index.js --------------------------------------入口文件

下次會在這個目錄的基礎上加上less,sass解析以及字體、圖片、多媒體文件的打包,而且加上代碼的分割,提取公共代碼等

參考文章

相關文章
相關標籤/搜索