webpack近幾年已經是前端的標準配備之一了,強大的功能將gulp, grunt, browserify的優點通通整合起來,以前需要學好幾種包裹,自動化流程,現在只需學一種,就是webpack。配上react和複雜的系統,以前只有後端所使用的編譯再執行,現在也發生在複雜的前端生態身上了。具備以下優點:
- 可引入特定模組解析js,jsx,css,scss,或是圖片,字型等等
- 可輕易載入更多客製化或彈性的loader
- 可載入模組解析ES6,stage0~3的js語法
- 可執行許多自動化的動作,包含最小化,加入hash等等
- 可拆分程式碼
單元 1. 利用webpack建制簡單的react開發環境
首先,先建置如下專案結構
|--build
|----Index.html
|--containers
|----App
|------App.jsx
|----Main.jsx
|--package.json
|--webpack.config.js
執行yarn init來初始化 package.json (你也可以用npm init來處理,這邊的例子都會以yarn來做套件管理)
{
"name": "reactStarter",
"version": "1.0.0",
"description": "build the initial environment for react",
"author": "Anderson",
"license": "MIT"
}
繼續安裝以下套件(例子中的webpack套件目前會先以v2.x為主)
yarn add babel-core
yarn add babel-loader
yarn add babel-preset-es2015
yarn add babel-preset-react
yarn add react
yarn add react-dom
yarn add webpack@2.4.1
- Index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
</head>
<body>
<div id="app"></div>
<script type="text/javascript" src="bundle.js"></script>
</body>
</html>
- Main.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App/App.jsx';ReactDOM.render(<App />, document.getElementById('app'))
- App.jsx
import React from 'react';class App extends React.Component {
render() {
return <h1>My First React App</h1>;
}
}export default App;
- webpack.config.js
var path = require('path');module.exports = { entry: './containers/Main.jsx', output: { path: path.resolve(__dirname, 'Build/'), filename: 'bundle.js' } module: { loaders: [{ test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader', query: { presets: ['es2015', 'react'] } }] }};
entry
: 需打包檔案執行的進入點,以React為例,通常是最一開始的進入點。
output
: 編譯完的檔案需放置的位置和檔名。
module
: 官方提供豐富的API,能幫助你編譯模組。這邊使用到的是能幫我們解析jsx的模組。
— test
: 利用正規表示式的寫法來讓系統了解該解讀那些格式的檔名。
— exclude
: 在打包時,要例外的資料夾。才不會將node_modules裡的檔案也一併打包。
— loader
: 因為專案會使用到es6,所以需要用Babel來解析。
— query
: 載入react和es6來解析React JSX和ES6語法。
程式的部分都完成了,於是我們在命令列中打上 webpack
,包裹完的bundle.js就會出現在Build的資料夾下了。
最後打開就資料夾下的Index.html就大功告成了。
單元 2. 加入熱加載,達到live reload功能
上面的例子中,當我們有需要修改元件時,如果每次都要執行webpack指令,使用上就顯得相當不方便,無法立即看到修改後的成果。所以我們這單元介紹的是webpack-dev-server這個套件的使用方式。
webpack-dev-server內建小型的express server,使用webpack-dev-middleware來達到webpack的動態包裹。
首先,先來安裝webpack-dev-server
yarn add webpack-dev-server@1.16.5
在webpack.config.js中module.exports底下多加入這一段來設定預設localhost下的port,webpack有會分成以下兩種模式來自動刷新頁面,
1. iframe mode: 網址要在中間多加上webpack-dev-server的字眼,如原本localhost:7777要改為localhost:7777/webpack-dev-server/index.html。,可以注意到上面會多一條狀態列有點不美觀,所以inline比較受歡迎。
2. inline mode: 使用上有兩種分式,一種是如下在webpack.config.js多加
inline:true
這段。另一種是在指令後方直接多加參數,如webpack-dev-server --inline
。
devServer: { inline: true, port: 7777},
最後就是在package.json的script中多加入這段,然後執行 yarn run dev
,連上 localhost:7777 就可以成功執行網站了。可以試著修改一下元件的內容,就會發現畫面可以自動刷新了。
"scripts": { "dev": "webpack-dev-server --devtool eval --progress --colors --hot --content-base build"}
附帶一提,介紹一下webpack-dev-server
後面參數的使用方式:
devtool eval
: 顯示發生錯誤的行數與檔案名稱progress
: 顯示包裹的完成進度colors
: 訊息加入顏色content-based build
指向專案最終輸出的資料夾,若沒有該指令,預設會指到根目錄下
單元 3. 加入css樣式
在App底下多加入App.css的檔案
|--build
|----Index.html
|--containers
|----App
|------App.js
|------App.css
|----Main.jsx
|--package.json
|--webpack.config.js
先安裝可以載入css的style-loader和css-loader
yarn add css-loader
yarn add style-loader
在webpack.config.js加入這些loader
var path = require('path');module.exports = { entry: './containers/Main.jsx', output: { path: path.resolve(__dirname, 'build/'), filename: 'bundle.js' }, devServer: { inline: true, port: 7777 }, module: { loaders: [ { test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel', query: { presets: ['es2015', 'react'] } }, { test: /\.css$/, exclude: /node_modules/, loader: 'style-loader!css-loader', }] }};
最後就是在App.css中加入一段css來看結果
h1 { color: blue;}
結果如下
單元 4. 改為載入scss
將單元3加入App.css改為App.scss,並安裝以下sass模組
yarn add sass-loaderyarn add sass-node
把webpack.config.js中,我們在單元3設定的css設定拿掉改為scss的設定
{ test: /\.scss$/, exclude: /node_modules/, loader: 'style-loader!css-loader!sass-loader'}
我們把原本在App.js中的html修改一下如下
...
import './App.scss';class App extends React.Component { render() { return ( <div> <h1>My First React App!</h1> <div className="title">scss works</div> </div>); }}...
再回頭來看我們剛才改的App.scss,
$font-size: 18px;$blue: #3498DB;h1 { color: lighten($blue, 10%);}.title { font-size: $font-size;}
結果如下
單元 5. 處理圖片
先安裝可以處理圖片的模組url-loader和file-loader
yarn add url-loaderyarn add file-loader
webpack.config.js多加入以下設定,其中限制10k以下會被壓縮成base64的字串來減低圖片傳輸的流量
{ test: /\.(png|jpg)$/, loader: 'url?limit=10240'}
在資料夾中插入一張圖案,並建立對應的資料夾
|--build
|----Index.html
|--containers
|----App
|------App.js
|------App.scss
|----Main.jsx
|--static
|----images
|------baby.jpg
|--package.json
|--webpack.config.js
在App.js中插入程式碼
...class App extends React.Component { render() { return ( <div> <h1>My First React App!</h1> <div className="title">scss works</div> <img src={require('../../static/images/baby.jpg')} alt="Smiley face" height="400" width="300" /> </div>); }}...
單元 6. 使用bootstrap 4
專案目錄改為如下,會新增以下黑體部分的檔案,
|--build
|----Index.html
|--containers
|----App
|------App.js
|------App.scss
|----Main.jsx
|--static
|----images
|------baby.jpg
|--styles
|----bootstrap
|------pre-customizations.scss
|------customizations.scss
|----fonts
|------OpenSans-Light.ttf
|----global.scss
|--.bootstraprc
|--postcss.config.js
|--package.json
|--webpack.config.js
在開始之前,先載入bootstrap對應的套件,
yarn add bootstrap@4.0.0-alpha.6 bootstrap-sass bootstrap-loader postcss-loader resolve-url-loader
新增完套件後,再來就是修改對應的設定讓bootstrap生效。
- .bootstraprc
# Output debugging info
loglevel: debug# Major version of Bootstrap: 3 or 4
bootstrapVersion: 4# If Bootstrap version 4 is used - turn on/off flexbox model
useFlexbox: true# Webpack loaders, order matters
styleLoaders:
- style-loader
- css-loader
- postcss-loader
- sass-loader# Extract styles to stand-alone css file
# Different settings for different environments can be used,
# It depends on value of NODE_ENV environment variable
# This param can also be set in webpack config:
# entry: 'bootstrap-loader/extractStyles'
extractStyles: false# env:
# development:
# extractStyles: false
# production:
# extractStyles: true
# Customize Bootstrap variables that get imported before the
# original Bootstrap variables. Thus original Bootstrap variables
# can depend on values from here. All the bootstrap variables are
# configured with !default, and thus, if you define the variable
# here, then that value is used, rather than the default. However,
# many bootstrap variables are derived from other bootstrap
# variables, and thus, you want to set this up before we load the
# official bootstrap versions. For example, _variables.scss
# contains: $input-color: $gray !default; This means you can define # $input-color before we load _variables.scss
preBootstrapCustomizations: ./styles/bootstrap/pre-customizations.scss# This gets loaded after bootstrap/variables is loaded and before
# bootstrap is loaded. A good example of this is when you want to
# override a bootstrap variable to be based on the default value of # bootstrap. This is pretty specialized case. Thus, you normally
# just override bootrap variables in preBootstrapCustomizations so
# that derived variables will use your definition.
# For example, in _variables.scss:
# $input-height: (($font-size-base * $line-height) + ($input-padding-y * 2) + ($border-width * 2)) !default;
# This means that you could define this yourself in
# preBootstrapCustomizations. Or you can do this in
# bootstrapCustomizations to make the input height 10% bigger than the default calculation.
# Thus you can leverage the default calculations.
# $input-height: $input-height * 1.10;
bootstrapCustomizations: ./styles/bootstrap/customizations.scss# Import your custom styles here. You have access to all the
# bootstrap variables. If you require your sass files separately,
# you will not have access to the bootstrap variables, mixins,
# clases, etc. Usually this endpoint-file contains list of @imports # of your application styles.
appStyles: ./styles/global.scss### Bootstrap styles
styles:# Mixins
mixins: true# Reset and dependencies
normalize: true
print: true# Core CSS
buttons: true
code: true
forms: true
grid: true
images: true
reboot: true
tables: true
type: true# Components
alert: true
badge: true
breadcrumb: true
button-group: true
card: true
close: true
custom-forms: true
dropdown: true
input-group: true
jumbotron: true
list-group: true
media: true
nav: true
navbar: true
pagination: true
progress: true
responsive-embed: true
transitions: true# Components JavaScript
carousel: false
modal: false
popover: false
tooltip: false# Utility classes
utilities: true### Bootstrap scripts
scripts: false
這邊使用YAML的語法,因為使用的是bootstrap 4版的,所以bootstrapVersion
設為4。另外要載入我們在先前章節提到的style-loader, css-loader, sass-loader, 另外多載入一個postcss-loader。preBootstrapCustomizations
會在載入bootstrap前載入,而bootstrapCustomizations
則會在載入bootstrap後載入,所以可以去複寫掉bootstrap內建的一些設定,改成客製化的基本設定,記得路徑要設為專案底下對應的檔案路徑。中間的屬性則是否需要載入的bootstrap元件,可看需要設定。因為使用react,所以不需要另外載入jquery,除了把components 中javascript區塊中的都設為false,以及最後一段的script: false
。如果需要在CLI中看載入元件的過程,可以在第一行的loglevel: debug
,如果不需要則設為false。
- pre-customizations.scss
$font-family-sans-serif: 'OpenSans-Light', Tahoma, "Helvetica Neue", Helvetica, Arial, sans-serif;// This path is relative to this file!
$fonts-url-path: '../fonts';@font-face {
font-family: 'OpenSans-Light';
src: url('#{$fonts-url-path}/OpenSans-Light.ttf') format('truetype');
}
在載入bootstrap之前,先載入字型檔,而其中的$fonts-url-path為該檔案的相對路徑,去參考專案中所引入的字型檔。
- customizations.scss
// Customize variables
$btn-secondary-bg: #6e88b7;
$btn-secondary-color: #fff;
在載入bootstrap之後,我們可以複寫掉bootstrap的設定。
- global.scss
html, body {
height: 100%;
background-color: #333;
}body {
color: #fff;
text-align: center;
text-shadow: 0 .05rem .1rem rgba(0,0,0,.5);
background: url('../static/images/sample.jpg') no-repeat;
background-size: 100% 100%;
}#app {
display: initial;
}
- webpack.config.js
...
module.exports = {
entry: [ 'bootstrap-loader', './containers/Main.jsx' ],
...
module: {
loaders: [
...
{
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'application/octet-stream'
}
},
},