前端工程不瞭解?帶你踩坑加爬坑。

JserWang發表於2018-08-13

本文希望能幫助那些一直用腳手架而對工程化沒有概念的朋友。

文中許多步驟會在執行時報錯,從錯誤中分析需要新增的配置,加深印象以及對所新增的每一行配置的理解。

本文將以React為例,帶你走一次。

建立目錄

mkdir demo && cd demo
npm init
touch index.js
複製程式碼

webpack

安裝webpack依賴

yarn add webpack webpack-cli --dev # 安裝webpack相關依賴
touch webpack.config.js # 新建webapck配置檔案
複製程式碼

修改配置

這是一份最基本的webpack配置:

const path = require('path');

module.exports = {
  entry: "./index.js",
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'my-first-webpack.bundle.js'
  }
};
複製程式碼

調整package.json

在package.json中,新增scipts如下:

"scripts": {
	"build": "webpack"
},
複製程式碼

初試build

在命令列中執行

npm run build
複製程式碼

你會看到如下警告:

WARNING in configuration The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment. You can also set it to 'none' to disable any default behavior. Learn more: webpack.js.org/concepts/mo…

由於webpack在4.0後,新增mode配置項,它為我們預設設定了production。但是該警告並沒有影響build的結果暫且忽略。 可以看到dist目錄已經生成了名為my-first-webpack.bundle.js檔案。

OK,最基本的配置已經完成,接下來引入React。

React

安裝react依賴

yarn add react react-dom # 安裝react相關依賴
複製程式碼

使用

在使用前,需要在dist目錄中,新增index.html,內容如下:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>React</title>
  </head>
  <body>
    <div id="root"></div>
    <script src="./my-first-webpack.bundle.js"></script>
  </body>
</html>

複製程式碼

react官網官網找段HelloWorld貼過來吧,全英文看不懂?沒關係,程式碼你總認識吧,貼就完了!

index.js中的內容變更如下:

import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(
  <h1>Hello, world!</h1>,
  document.getElementById('root')
);
複製程式碼

OK,看似完美,執行下,build看看效果。

ERROR in ./index.js 4:16
Module parse failed: Unexpected token (4:16)
You may need an appropriate loader to handle this file type.
| import ReactDOM from 'react-dom';
|
> ReactDOM.render(<div>Hello World</div>,
|   document.getElementById('root'));
複製程式碼

報錯了?莫慌,從錯誤資訊中找關鍵字,You may need an appropriate loader to handle this file type.。 這時候感慨一句,程式設計師是偉大的,錯誤資訊很詳細了,告訴我們需要適當的loader來處理這個檔案。什麼loader?別問我,不是我乾的,繼續往下看剛才的連結下一小節react-jsx的介紹,拉到最下面,是不是有一段關於官方的建議?繼續查詢關鍵字,是不是看到一個叫Babel的東西?納尼,莫非jsx和它有關係?雖然這段話是說推薦編輯器設定的吧,但是程式設計師必備一顆好奇的心。

Babel

Google一下上面的關鍵詞Babel進去瞅瞅吧。 於是開始接觸一個新名詞Babel,這玩意幹啥的?能為我們帶來什麼?看看首頁吧。

  • ES2015 及更高版本

    Babel 通過語法轉換器支援最新版本的 JavaScript 。

  • Polyfill

    由於 Babel 只轉換語法(如箭頭函式), 你可以使用 babel-polyfill 支援新的全域性變數,例如 Promise 、新的原生方法。

  • JSX 和 Flow

    Babel 能夠轉換 JSX 語法並去除型別註釋。

  • 可插拔

    Babel 是建立在外掛之外的。 你可以使用已有的外掛或者自己編寫外掛來組成屬於你自己的轉換管道。

  • 可調式

    支援 Source map 因此可以輕鬆除錯編譯後程式碼。

看完首頁的介紹,是否和我有同樣的感嘆:好東西啊!既然是好東西,用起來吧。 從配置webpack選項中,你會發現剛才出現的兩個關鍵字都來了babelloader,艾瑪,得來全不費工夫。

yarn add babel-loader babel-core babel-preset-env babel-polyfill babel-preset-react --dev 
# 這波安裝比較長?因為我們把剛才看到的es2015、更高版本語法的,polyfill,jsx的都裝上了
複製程式碼

通過config配置

webpack.config.js修改配置如下:

const path = require('path');

module.exports = {
  entry: "./index.js",
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'my-first-webpack.bundle.js'
  },
  module: {
    rules: [
      { test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
    ]
  }
};
複製程式碼

建立.babelrc配置檔案

touch .babelrc #建立.babelrc
複製程式碼

將以下內容貼上至.babelrc中:

{
  "presets": ["env", "react"]
}
複製程式碼

至此,已經將上面的babel-preset-envbabel-preset-react使用上了,那polyfill怎麼用呢?繼續看波文件吧。emmm,寫的很清楚了,我們把polyfill使用上吧,修改webpack.config.js中的配置如下:

const path = require('path');

module.exports = {
  entry: ["babel-polyfill", "./index.js"],
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'my-first-webpack.bundle.js'
  },
  module: {
    rules: [
      { test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
    ]
  }
};
複製程式碼

該配置的都配置完了,執行下npm run build看看效果?果不其然,編譯過了。

你以為工程就這樣配完了嗎?NO,這僅僅是個開始!

react-router

SPA工程中使用,什麼是SPA,單頁應用?什麼是單頁應用?只有一個html,公用js css僅引用一次,通過區域性重新整理渲染的應用。

react-router官網,按著快速上手的步驟來。

安裝

yarn add react-router-dom
複製程式碼

使用

Now you can copy/paste any of the examples into src/App.js. Here’s the basic one:

這裡從create-react-app中使用方式,雖然我們不是,但是我們自己搭的也不差啊。自己建個srcApp.js吧。

mkdir src && touch src/App.js
複製程式碼

將官方的?貼進來App.js

import React from 'react'
import {
  BrowserRouter as Router,
  Route,
  Link
} from 'react-router-dom'

const Home = () => (
  <div>
    <h2>Home</h2>
  </div>
)

const About = () => (
  <div>
    <h2>About</h2>
  </div>
)

const Topic = ({ match }) => (
  <div>
    <h3>{match.params.topicId}</h3>
  </div>
)

const Topics = ({ match }) => (
  <div>
    <h2>Topics</h2>
    <ul>
      <li>
        <Link to={`${match.url}/rendering`}>
          Rendering with React
        </Link>
      </li>
      <li>
        <Link to={`${match.url}/components`}>
          Components
        </Link>
      </li>
      <li>
        <Link to={`${match.url}/props-v-state`}>
          Props v. State
        </Link>
      </li>
    </ul>

    <Route path={`${match.path}/:topicId`} component={Topic}/>
    <Route exact path={match.path} render={() => (
      <h3>Please select a topic.</h3>
    )}/>
  </div>
)

const BasicExample = () => (
  <Router>
    <div>
      <ul>
        <li><Link to="/">Home</Link></li>
        <li><Link to="/about">About</Link></li>
        <li><Link to="/topics">Topics</Link></li>
      </ul>

      <hr/>

      <Route exact path="/" component={Home}/>
      <Route path="/about" component={About}/>
      <Route path="/topics" component={Topics}/>
    </div>
  </Router>
)
export default BasicExample
複製程式碼

接下來在index.js中引用:

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

ReactDOM.render(
  <App />,
  document.getElementById('root')
);
複製程式碼

執行npm run build看看。沒報錯,使用瀏覽器開啟dist/index.html看看。點選連結沒反應?什麼情況?莫慌,開啟控制檯看看:

Uncaught DOMException: Failed to execute 'pushState' on 'History': A history state object with URL 'file:///' cannot be created in a document with origin 'null' and URL

emmmm,咋整?別問我,真不是我乾的… 既然chrome不好使,就再看一眼safari下好不好用吧,一樣不好使,再看一眼報錯資訊。

[Error] SecurityError: Blocked attempt to use history.pushState() to change session history URL from file:///demo/dist/index.html to file:///about. Paths and fragments must match for a sandboxed document.

好像safari的報錯更友好一些,我們可以清楚的看到,它在試圖改變連結,為了安全起見,你認為這麼做合理麼?豈不是拿個html能訪問計算機任何檔案了?emmm,果然不合理。再看關鍵詞: Paths and fragments must match for a sandboxed document

那我們就構建個沙盒環境吧。

webpack-dev-server

配置參考連結

安裝

yarn add webpack-dev-server --dev
複製程式碼

修改配置

  • package.json中新增scripts

    "dev": "webpack-dev-server"
    複製程式碼
  • webpack.config.js根節點中,新增:

      devServer: {
        contentBase: path.join(__dirname, 'dist'),
        compress: true,
        port: 9000
      }
    複製程式碼
  • 執行上面剛新增的srcripts

    npm run dev
    複製程式碼
  • 瀏覽器中開啟連結localhost:9000

功能沒問題,樣式沒法忍,有木有?改!

  1. src中新建app.css檔案,新增如下內容:

    .container {
      list-style: none;
    }
    複製程式碼
  2. App.js中,新增如下程式碼:

    import './app.css';
    複製程式碼
  3. BasicExample中的ul應用樣式:

    <ul className="container">
    	<li><Link to="/">Home</Link></li>
    	<li><Link to="/about">About</Link></li>
    	<li><Link to="/topics">Topics</Link></li>
    </ul>
    複製程式碼

這時,你會發現一個熟悉的錯誤。

You may need an appropriate loader to handle this file type.

這次我們可以很快的定位到,缺少載入css相關的loader

再次與loader相遇

webpack相關文件 雖然,webpack的文件總是那麼的不及時,但是一些基礎性的東西,還是能從中學到的。既然又一次遇到了loader,不妨這次我們就徹底搞明白什麼是loader,它為我們提供了什麼?

loader 用於對模組的原始碼進行轉換。loader 可以使你在 import 或"載入"模組時預處理檔案。因此,loader 類似於其他構建工具中“任務(task)”,並提供了處理前端構建步驟的強大方法。loader 可以將檔案從不同的語言(如 TypeScript)轉換為 JavaScript,或將內聯影像轉換為 data URL。loader 甚至允許你直接在 JavaScript 模組中 import CSS檔案!

看完這麼長一段,我總結了一句話,通過import來處理的檔案,需要對應的loader。既然如此,那就一個一個安吧。

css-loader

安裝

yarn add style-loader css-loader --dev
複製程式碼

配置

修改webpack.config.js中,module下的rules,就像新增babel-loader一樣,新增如下配置:

  {
    test: /\.css$/,
    use: [
      'style-loader',
      'css-loader'
    ]
  }
複製程式碼

關於css-loader這裡要再多提一句,當你不想對全域性css進行汙染,想通過以下方式使用時:

import styles from 'app.css';

<div className={styles.container} />
複製程式碼

請使用css module,webpack配置css module的方式也十分簡單:

'css-loader?modules&localIdentName=[name]-[hash:base64:5]',
複製程式碼

css-loader調整成以上內容即可。

file-loader

處理各種圖示、圖片檔案

安裝

yarn add file-loader --dev
複製程式碼

配置

修改webpack.config.js中,module下的rules,新增如下配置:

{
	test: /\.(png|svg|jpg|gif)$/,
	use: [
	  'file-loader'
	]
}
複製程式碼

字型檔案依舊由file-loader處理,繼續新增配置:

{
	test: /\.(woff|woff2|eot|ttf|otf)$/,
	use: [
	  'file-loader'
	]
}
複製程式碼

loader暫時新增到這裡,這時記住了沒?想讓webpack處理對應檔案,就要有對應的loader

繼續重新整理看我們的demo工程,生效了。

初識Plugin

loader配置完,繼續按著文件來吧,看看我們還有什麼可以瞭解的。

外掛是 webpack 的支柱功能。webpack 自身也是構建於,你在 webpack 配置中用到的相同的外掛系統之上!

外掛目的在於解決 loader 無法實現的其他事。

html-webpack-plugin

管理輸出中有這麼一段:

如果我們更改了我們的一個入口起點的名稱,甚至新增了一個新的名稱,會發生什麼?生成的包將被重新命名在一個構建中,但是我們的index.html檔案仍然會引用舊的名字。我們用 HtmlWebpackPlugin 來解決這個問題。

OK,瞭解了它的目的,有用,裝!

安裝

yarn add html-webpack-plugin --dev

複製程式碼

配置

webpack.config.js的根節點中新增plugins:

  // 引入html-webpack-plugin
  const HtmlWebpackPlugin = require('html-webpack-plugin');
複製程式碼
  plugins: [
    new HtmlWebpackPlugin({
      title: 'Output Management'
    })
  ],
複製程式碼

重啟下npm run dev,你會發現頁面空白了?臥槽,這不是坑麼?開啟控制檯看一眼,Target container is not a DOM element.,再看一眼Elements選項卡中的內容,發現,咦。好像我們的<div id="root"></div>神奇的消失了。 再看文件,發現這麼一句話:

如果你想要了解更多 HtmlWebpackPlugin 外掛提供的全部功能和選項,那麼你就應該多多熟悉 HtmlWebpackPlugin 倉庫。 其中的配置項中,template這項是這麼描述的: webpack require path to the template. Please see the docs for details

模板啊,我們把dist/index.html中的檔案挪出來,放到專案的根目錄下,然後再修改下webpack.config.js中的配置:

new HtmlWebpackPlugin({
  title: 'Demo',
  template: './index.html'
})
複製程式碼

重啟下服務看看吧,npm run dev

頁面出來了,但是報了個錯:only one instance of babel-polyfill is allowed。 這又是什麼錯?我們明明只有一個entry,為什麼說引了多次呢?開啟Elements選項卡中,驚奇的發現,原來是我們剛才直接從dist目錄中挪的index.html中,還存在<script src="./my-first-webpack.bundle.js"></script>這麼一段script,刪掉,再重啟。大功告成。

clean-webpack-plugin

你可能已經注意到,由於過去的指南和程式碼示例遺留下來,導致我們的 /dist 資料夾相當雜亂。webpack 會生成檔案,然後將這些檔案放置在 /dist 資料夾中,但是 webpack 無法追蹤到哪些檔案是實際在專案中用到的。

依然有用,依然裝!

安裝

yarn add clean-webpack-plugin --dev
複製程式碼

配置

修改webpack.config.js: 引入CleanWebpackPlugin:

const CleanWebpackPlugin = require('clean-webpack-plugin');
複製程式碼

新增plugins

new CleanWebpackPlugin(['dist']),
複製程式碼

區分生產環境與開發環境

為什麼要區分生產環境與開發環境?

開發環境(development)和生產環境(production)的構建目標差異很大。在開發環境中,我們需要具有強大的、具有實時重新載入(live reloading)或熱模組替換(hot module replacement)能力的 source map 和 localhost server。而在生產環境中,我們的目標則轉向於關注更小的 bundle,更輕量的 source map,以及更優化的資源,以改善載入時間。由於要遵循邏輯分離,我們通常建議為每個環境編寫彼此獨立的 webpack 配置。

拆分webpack配置

按照官方教程,來進行拆分。在此,我更推薦新建config目錄,將配置統一放置config中,所以此時我們的配置檔案應該是:

config/webpack.common.js:

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

module.exports = {
  entry: ["babel-polyfill", "./index.js"],
  output: {
    path: path.resolve(__dirname, '../dist'),
    filename: '[name].[contenthash:12].js'
  },
  module: {
    rules: [
      { 
        test: /\.js$/, 
        exclude: /node_modules/,
        loader: "babel-loader?cacheDirectory" 
      },
      {
        test: /\.css$/,
        use: [
          'style-loader',
          "css-loader"
        ]
      },
      {
        test: /\.(png|svg|jpg|gif)$/,
        use: [
          'file-loader'
        ]
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        use: [
          'file-loader'
        ]
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin(["dist"], {
      root: path.resolve(__dirname, "../"),
    }),
    new HtmlWebpackPlugin({
      title: 'Demo',
      template: './index.html'
    })
  ]
};
複製程式碼

config/webpack.dev.js:

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

module.exports = merge(common, {
  mode: 'development',
  devtool: 'inline-source-map',
  devServer: {
    contentBase: path.resolve(__dirname, '../dist'),
    compress: true,
    port: 9000
  }
});
複製程式碼

config/webpack.prod.js

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

module.exports = merge(common, {
  mode: 'production',
});
複製程式碼

另外,package.json中的scripts也要進行相應的調整:

"build": "webpack --config config/webpack.prod.js",
"dev": "webpack-dev-server --config config/webpack.dev.js"
複製程式碼

關於分離css

extract-text-webpack-plugin【4.0已廢棄】

tips: 這是一個從入門到放棄的Plugin,感興趣的話可以繼續跟著操作,沒興趣請跳至下個小節。

它會將所有的入口 chunk(entry chunks)中引用的 *.css,移動到獨立分離的 CSS 檔案。

安裝
yarn add extract-text-webpack-plugin --dev
複製程式碼
配置

照著文件中的?把配置貼進來,修為webpack.config.js

const path = require('path');
const ExtractTextPlugin = require("extract-text-webpack-plugin");

module.exports = {
  mode: "production",
  entry: ["babel-polyfill", "./index.js"],
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'my-first-webpack.bundle.js'
  },
  module: {
    rules: [
      { 
        test: /\.js$/, 
        exclude: /node_modules/,
        loader: "babel-loader?cacheDirectory" 
      },
      {
        test: /\.css$/,
        use: ExtractTextPlugin.extract({
          fallback: "style-loader",
          use: "css-loader"
        })
      },
      {
        test: /\.(png|svg|jpg|gif)$/,
        use: [
          'file-loader'
        ]
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        use: [
          'file-loader'
        ]
      }
    ]
  },
  plugins: [
    new ExtractTextPlugin("styles.css"),
  ],
  devServer: {
    contentBase: path.join(__dirname, 'dist'),
    compress: true,
    port: 9000
  }
};
複製程式碼

重啟服務的時候,你會發現報錯了?WTF?費了半天勁,結果還不能用?這時候我們需要注意一點,就是它曾經肯定是能用的,不然不能放到文件上,這就體現出來webpack文件落後了。既然如此,因為我們當下使用的是webpack 4.x的版本,這時候先去ExtractTextWebpackPlugin的github上搜搜有沒有想過issue吧,關鍵詞webpack 4。 看到一個issue

@vasivas don't use extract-text-webpack-plugin for extract css, please use github.com/webpack-con…

竟然還有這種操作,那就看看這個mini-css-extract-plugin

關於webpack,就引導到這裡,本文不是對webpack進行講解,更多關於webpack的部分,可以看: @花褲衩 寫的文章:

手摸手,帶你用合理的姿勢使用webpack4(上)

手摸手,帶你用合理的姿勢使用webpack4(下)

最終我們關於分離css的內容變成如下: webpack.common.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  entry: ["babel-polyfill", "./index.js"],
  output: {
    path: path.resolve(__dirname, '../dist'),
    filename: '[name].[contenthash:12].js'
  },
  module: {
    rules: [
      { 
        test: /\.js$/, 
        exclude: /node_modules/,
        loader: "babel-loader?cacheDirectory" 
      },
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader?modules&localIdentName=[name]-[hash:base64:5]',
        ]
      },
      {
        test: /\.(png|svg|jpg|gif)$/,
        use: [
          'file-loader'
        ]
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        use: [
          'file-loader'
        ]
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin(["dist"], {
      root: path.resolve(__dirname, "../"),
    }),
    new HtmlWebpackPlugin({
      title: 'Demo',
      template: './index.html'
    }),
  ]
};
複製程式碼

webpack.prod.js

const merge  = require('webpack-merge');
const common = require('./webpack.common');
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = merge(common, {
  mode: 'production',
  optimization: {
    minimizer: [
      new UglifyJsPlugin({
        cache: true,
        parallel: true,
        sourceMap: true 
      }),
      new OptimizeCSSAssetsPlugin({})  // use OptimizeCSSAssetsPlugin
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].[contenthash:12].css',
      chunkFilename: '[name].[contenthash:12].css'  // use contenthash *
    })
  ]
});
複製程式碼

webpack.dev.js

const merge  = require('webpack-merge');
const common = require('./webpack.common');
const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = merge(common, {
  mode: 'development',
  devtool: 'inline-source-map',
  devServer: {
    contentBase: path.resolve(__dirname, '../dist'),
    compress: true,
    port: 9000
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].css',
      chunkFilename: '[id].css',
    }),
  ]
});
複製程式碼

程式碼分離

依舊看上面 @花褲衩 的文章,分的很細膩。在此我們簡單分離:

webpack.common.js中修改:

const merge  = require('webpack-merge');
const common = require('./webpack.common');
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = merge(common, {
  mode: 'production',
  optimization: {
    minimizer: [
      new UglifyJsPlugin({
        cache: true,
        parallel: true,
        sourceMap: true 
      }),
      new OptimizeCSSAssetsPlugin({})  // use OptimizeCSSAssetsPlugin
    ],
    runtimeChunk: {
      name: "manifest"
    },
    splitChunks: {
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: "vendors",
          priority: -20,
          chunks: "all"
        }
      }
    }
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].[contenthash:12].css',
      chunkFilename: '[name].[contenthash:12].css'  // use contenthash *
    })
  ]
});
複製程式碼

OK,看似完美。

ReactBabelwebpack都有了,接下來就是為了自己與團隊之間協作程式碼的規範性,要通過下一個工具了。

Eslint

官網

安裝

npm install eslint -g #全域性安裝eslint
複製程式碼

初始化

eslint --init
複製程式碼

選擇預設配置

? How would you like to configure ESLint? Use a popular style guide
? Which style guide do you want to follow? Airbnb (https://github.com/airbnb/javascript)
? Do you use React? Yes
? What format do you want your config file to be in? JavaScript
Checking peerDependencies of eslint-config-airbnb@latest
? The style guide "airbnb" requires eslint@^4.19.1. You are currently using eslint@5.2.0.
  Do you want to downgrade? Yes
複製程式碼

在此直接選擇airbnb

調整配置

在初次安裝後,我們發現我們之前的App.js報錯了,這時我們需要調整eslint相關的配置規則,來讓它更符合我們預期的使用: 開啟.eslintrc.js檔案,調整內容如下:

module.exports = {
  "extends": "airbnb",
  "plugins":[
    "react",
    "jsx-a11y",
    "import"
  ],
  "rules": {
    "import/no-extraneous-dependencies": "off",
    "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],
    "react/prop-types": 0
  }
};
複製程式碼

更多eslint的使用姿勢,還需要你個人進行探索。

引入ant-design

官網

安裝

yarn add antd
複製程式碼

按需載入

若不想每次引用css時,可選用,在這裡使用babel-plugin-import

yarn add babel-plugin-import --dev
複製程式碼

修改.babelrc檔案中修改為:

{
  "presets": ["env", "react"],
  "plugins": [
    ["import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css" }]
  ]
}
複製程式碼

試用

App.js中,進行引用:


import { DatePicker } from 'antd';

const Home = () => (
  <div>
    <h2>
      <DatePicker />
    </h2>
  </div>
);
複製程式碼

重新整理後我們發現,元件是顯示出來了,但是樣式並沒有生效。繼續去找解決方案: www.jianshu.com/p/603a61471… 這位老哥寫的很清楚了,原來是我們的rules配置還有點瑕疵,根據內容調整如下:

  {
    test: /\.css$/,
    exclude: /node_modules/,
    use: [
      MiniCssExtractPlugin.loader,
      'css-loader?modules&localIdentName=[name]-[hash:base64:5]',
    ],
  },
  {// antd樣式處理
    test: /\.css$/,
    exclude: /src/,
    use: [
      { loader: 'style-loader' },
      {
        loader: 'css-loader',
        options: {
          importLoaders: 1,
        },
      },
    ],
  },

複製程式碼

調整完後,重啟webpack

最後

本文只做引子,讓你對前端工程化有一定的瞭解,更多的還需自己去根據關鍵字探索。

本人上上週搞得的基於百度地圖的封裝現已開源,歡迎加入一起搞事情:

github

官網