一步一步使用webpack+react+scss腳手架重構項目

  前幾天作了一個項目:【node】記錄項目的開始與完成——pipeline_kafka流式數據庫管理項目;由於開發時間緊迫,淺略的使用了一下react,感受這個ui庫很是的符合個人口味,如今趁着有空閒時間,將項目前端重構一番。這裏面存在一些坑,都是深不見底的水坑,說多了都是淚水。。。好在順利完成,如今在這裏再一步一步重來一遍,和須要學習webpack的前端童鞋分享。javascript

準備

tips:文章最後可下載democss

一:目錄html

  

  首先咱們要新建目錄,前端

  

  新建app文件夾,它存放入口文件,component組件,java

  新建static文件夾存放打包後的文件,node

  新建webpack文件夾,存放的webpack配置文件。react

2、生成package.jsonwebpack

  在當前目錄打開cmd或者PowerShell或者終端,es6

  

  輸入npm init 而後一直回車到執行完畢,package.json就滾到文件夾根目錄下面了web

 三、安裝webpack

  shell輸入 webpack i webpack --save 安裝webpack

  

  我成功後的提示是這樣的。

4、新建文件

  在目錄app中新建main.js,

  在目錄webpack中新建webpack的配置文件  webpack.config.js

  在目錄static中新建一個  index.html

  在目錄static中新建一個js目錄

5、初步配置

  首先寫一下 /static/index.html這個文件,由於生成的文件目錄在 /static/js文件夾裏面,因此這裏要預先引用打包後的文件,最後訪問這個html文件就能夠看到效果

  

複製代碼
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
        <title>webpack_Demo</title>
    </head>
    <body>
        <div class="content">
        </div>
        <script src="./js/app.js" type="text/javascript" charset="utf-8"></script>
    </body>
</html>
複製代碼

  而後配置webpack.config.js:

  剛開始咱們就配一個簡單的入口和輸出目錄就能夠了: 

複製代碼
var path = require("path");

module.exports = {
    entry:{  //入口文件
        "app":path.join(__dirname,"../app/main.js")  //app對應生成的文件名
    },
    output:{
        path:path.join(__dirname,"../static/js/"),
        filename:"[name].js"   //這裏[name]就是表示對應entry對象的name,而後生成的後戳是.js
    }
}
複製代碼

  如今咱們就能夠簡單的測試一下,在/app/main.js中隨意寫一些代碼 ,好比alert(1)。

  在shell中調用webpack測試,運行:

  webpack --config ./webpack/webpack.config.js

   

  成功後訪問index.html,查看效果,若是報錯,多是缺乏哪一個依賴包,安裝後重覆上面步驟。

  這個時候文件目錄就變成了:

   app.js就是打包後生成的文件。

  如今咱們要把打包命令放在package.json裏,由於每次編譯都要運行那麼長的命令,太痛苦了。在package.json簡單的配置一個script就可使用npm run xxx運行了,編輯package.json:

  

複製代碼
{
  "name": "web_pack",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build":"webpack --config ./webpack/webpack.config.js" //添加一個build 值是打包用到的命令
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "webpack": "^3.0.0"
  }
}
複製代碼

如今在shell裏運行 npm run build就能夠編譯了

到這一步,初步的配置就算是完成了,接下來配置一個webpack-dev-server,而後就能夠配置react組件,生成項目了

 

配置webpack-dev-server 

  什麼是webpack-dev-server? 

  它是用來監控文件的修改事件,啓動它的時候,會分配一個端口,指向當前的目錄,一旦目錄下文件被修改,它會通知瀏覽器自動刷新頁面,省去了不斷的按f5的煩惱。

  在shell中安裝,運行:

  npm i webpack-dev-server --save-dev

  安裝成功後,運行:

  node_modules/.bin/webpack-dev-server --config ./webpack/webpack.config.js --port 8089 --open

  --config 是webpack配置文件目錄,--port 是運行的端口號 

  運行成功會在系統默認瀏覽器彈出一個窗口,這是一個選擇文件夾的界面,咱們訪問static,就能夠訪問到index.html了:

  

  這裏須要注意的一點是,你還須要將index.html中的app.js引用改爲http://localhost:8089/app.js,由於webpack-dev-server加載的是虛擬文件,目錄在根目錄下,因此須要修改這裏。  

<script src="http://localhost:8089/app.js" type="text/javascript" charset="utf-8"></script>

  項目完成後再改爲對應的路徑。

  修改完成,修改一下main.js中的js代碼,再看看瀏覽器中頁面是否改變。webpack-dev-server大體就配置好了,另外附上它的api地址:

  webpack-dev-server

 最後再把命令配置到package.json中

複製代碼
{
  "name": "web_pack",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "node_modules\.bin\webpack-dev-server --config ./webpack/webpack.config.js --port 8089 --open",  //添加到test中 
    "build":"webpack --config ./webpack/webpack.config.js" 
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "webpack": "^3.0.0"
  }
}
複製代碼

如今運行npm start test 就能夠開始開發了。

 

配置react

  到了這一步,咱們要開始配置react,首先仍是安裝依賴包,編譯jsx文件須要用到babel、babel-core、babel-loader、babel-preset-es201五、babel-preset-react、還有react本身的react、react-dom。安裝他們:

  npm i babel babel-core babel-loader babel-preset-es2015 babel-preset-react react react-dom --save

  安裝成功以後,先在main.js寫一個demo

  

複製代碼
var React = require("react");
var ReactDOM = require("react-dom");
ReactDOM.render(
        <div>
            <h1>welcome</h1>
        </div>
        ,document.querySelector(".content")
    );
複製代碼

  這裏必定要用 ReactDOM.render 老的版本react.render會報語法錯誤。

配置babel-loader 

  在webpack.config.js添加babel-loader用來解析jsx和es6的代碼:

  

複製代碼
var path = require("path");

module.exports = {
    entry:{
        "app":path.join(__dirname,"../app/main.js") //入口文件 name對應輸出的[name]
    },
    output:{
        path:path.join(__dirname,"../static/js/"), //輸出路徑
        filename:"[name].js"        //輸出app.js
    },
    module:{
        loader:[
            {
                test:/\.(js|jsx)$/,    //這是配置加載文件的規則 值是正則表達式 這裏寫的意思是.js .jsx結尾的文件加載loader
                loader:"babel-loader",
                exclude:/node_module/,        //這個目錄不須要加載loader
                query:{
                    presets:["react","es2015"]        //加載loader的presets
                }
            }
        ]
    }
}
複製代碼

  配置了module下面的loaders。

  而後npm run test 開啓服務,測試一下代碼是否能夠運行。

  順利的話,這裏應該能看到welcome了:

  

 

  如今的代碼結構顯然過於簡單,下面咱們在app文件目錄下新建兩個目錄 component 和 views。

  先在component 文件夾下新建hello.jsx,寫一些代碼:

複製代碼
import React from "react";

class Hello extends React.Component{
    constructor(props){
        super(props);
        this.propTypes = {
            text:React.PropTypes.string
        }
    }
    render(){
        return <div className="hello">
                    hello <span>{this.props.text}</span>
                </div>
    }
}
module.exports = Hello;
複製代碼

  通常個人import 語法用來表示react組件或其餘資源的引入,require語法用來表示js的引入,另外這裏用的是es6的class語法。關於es6,在文章下面有淺略說明。

  而後再views新建index.jsx,這裏能夠寫主要的頁面代碼:

複製代碼
import React from 'react';
import Hello from "../component/hello.jsx"; //引入hello組件

class Index extends React.Component{
    render(){
        return <div className="index_container">
                    <Hello text="world"></Hello>
                </div>
    }
}

module.exports = Index;
複製代碼

 最後main.js引入index,把index加入rander就能夠看到效果了:

複製代碼
var React = require("react");
var ReactDOM = require("react-dom");

import Index from "./views/index.jsx"; //引入index
ReactDOM.render(
        <div>
            <Index></Index>  //插入index視圖
        </div>
        ,document.querySelector(".content")
    );
複製代碼

查看效果:

到了這一步,基本的視圖結構就完成了,接下來配置css的加載,基本和react的方式同樣,加載對應的loader,解析對應的文件。

 

 

 

配置css:

  視圖解決了,如今咱們要解決css的引入問題,這裏能夠選擇的就比較多 css、sass、less等均可以,我選擇的是css,由於個人sass文件可使用ruby的sass編譯,在編輯保存時已經自動編譯成css了,我的以爲這樣管理起來更加方便。

  首先仍是安裝依賴,運行:

  npm i css-loader file-loader style-loader url-loader --save-dev

  file-loader url-loader 是用來編譯圖片資源的,它會將url()中的靜態資源打包編譯成base64格式,這裏須要注意,不要在css中寫找不到文件的路徑,不然會報錯編譯失敗。

  安裝完成後配置css-loader:

  

複製代碼
var path = require("path");

module.exports = {
    entry:{
        "app":path.join(__dirname,"../app/main.js") //入口文件 name對應輸出的[name]
    },
    output:{
        path:path.join(__dirname,"../static/js/"), //輸出路徑
        filename:"[name].js"        //輸出app.js
    },
    module:{
        loaders:[
            {
                test:/\.(js|jsx)$/,    //這是配置加載文件的規則 值是正則表達式 這裏寫的意思是.js .jsx結尾的文件加載loader
                loader:"babel-loader",
                exclude:/node_module/,        //這個目錄不須要加載loader
                query:{
                    presets:["react","es2015"]        //加載loader的presets
                }
            },
            {
                test:/\.css$/, //配置.css後戳的解析
                loader:"style-loader!css-loader"
            },
       {
         test:/\.(png|jpg)$/, //配置靜態文件解析
         loader:"url-loader?limit=8192"
       } ] } }
複製代碼

注意style-loader必須寫在css-loader前面,不然就會報錯

  配置完成,在hello.jsx引入個css瞧瞧(這裏要重啓一下test):

  

 引入的方法是

import "./hello.css";

引入成功,這樣css就可使用了

 

項目結構

  到目前爲止 項目的結構是這樣的:

  

  app中存放 組件(component)、視圖(views)、入口文件 。

  static中存放打包後的項目文件。

  webpack中存放webpack的配置文件

  建議將公共組件打包,好比建一個hello文件夾,裏面存放hello.jsx和hello.css以及須要的插件、文檔,這樣它的多項目複用將變得很是方便,拷貝文件便可。

淺談es6以及react中的小坑

  es6的class關鍵字看起來很性感,實際上也只是整了個容,感受內在變化很少。與createClass差異不是很大,在react中每次生命組件都要繼承React.Component。

  好比上面的hello.jsx:

複製代碼
constructor(props){
        super(props);
        this.propTypes = {
            text:React.PropTypes.string
        }
    }
複製代碼

  這是構造函數,就是new xxx()調用的那個函數,這裏爲啥要super? 這是個奇怪的寫法,緣由是由於構造函數中訪問不到this,須要調用super()才能順利訪問到this,這裏我的尤其不解,雖然理解起來也不難,構造函數屬於static方法,這裏爲啥不能和java同樣的邏輯,構造函數只能訪問類?

   this.propTypes  

   這個屬性標明瞭組件中全部用到的props 而且能驗證傳入的值的正確性,感受組件有它很是有必要,建議寫props不要少了這個屬性。

 react 中this的坑

  在hello.jsx組件上添加一個click事件,在事件中打印this:

複製代碼
class Hello extends React.Component{
    constructor(props){
        super(props);
        this.propTypes = {
            text:React.PropTypes.string
        }
    }
    render(){
        return <div className="hello" onClick={this.print}>
                    hello <span>{this.props.text}</span>
                </div>
    }
    print(){
        console.log("點擊事件");
        console.log(this);
    }
}
複製代碼

   會發現this的值既不是點擊dom也不是class而是null:

  

  但是若是在靜態文件中寫React.createClass則不會出現null。

  個人解決辦法是在render中強制指定this爲class: 

複製代碼
render(){
        this.print = this.print.bind(this);//綁定this到函數
        return <div className="hello" onClick={this.print}>
                    hello <span>{this.props.text}</span>
                </div>
    }
複製代碼

查看官方文檔解釋是:

  React.createClass有一個內置的魔術功能,能夠自動綁定全部方法this。這對於在其餘類中不用於此功能的JavaScript開發人員來講可能會有點混亂,或者當從React轉到其餘類時可能會使人困惑。所以,咱們決定不將此內置到React的類模型中。若是須要,您仍然能夠在構造函數中明確地預處理方法。
 
在遇到點擊更改state時,必定會用到this。要注意this的指向問題

總結

  前端就像是一隻正當壯年的母雞,今天下個蛋,明天下個蛋,是寡蛋是好蛋不知道,今天的蛋和明天的蛋嚐起來味道也差很少。咱們就像是飼養員,負責給母雞送吃的,下了蛋就要立刻負責收,不然要麼就爛了、要麼就孵出小雞吃不了雞蛋了。

  那些層出不窮的框架,壞掉的框架、已經變的強大就很難駕馭的框架,這對前端來講是一個考驗。

相關資源

  下載我最終作好的demo

   react文檔翻譯(快速入門)
  
轉載請註明出處(完)
相關文章
相關標籤/搜索