webpack、sass、react、redux的簡易demo入門

最開始只是想綜合的初略學習下這幾種技術,因此萌生了搭建一個簡單的結構的想法;整個結構應該沒有什麼問題;已經放到了github上,地址:webpack、sass、react、redux的簡易demo入門javascript

webpack

本質上,webpack 是一個現代 JavaScript 應用程序的靜態模塊打包器(module bundler)。當 webpack 處理應用程序時,它會遞歸地構建一個依賴關係圖(dependency graph),其中包含應用程序須要的每一個模塊,而後將全部這些模塊打包成一個或多個 bundle。

我本身對webpack的使用也不是很熟練,尚未很明白webpack的設計思惟,因此在配置的時候也是一臉懵逼,跟着官方文檔和一些社區的文章來一步一步配置,主要仍是須要知道這幾個配置:css

  • 入口(entry)
  • 輸出(output)
  • loader
  • 插件(plugins)
  • 解析(Resolve)

入口(entry)

起點或是應用程序的起點入口。從這個起點開始,應用程序啓動執行。若是傳遞一個數組,那麼數組的每一項都會執行。html

entry字段能夠是string | [string] | object { <key>: string | [string] }或者是函數【函數返回值是上面的三種類型中的一種】,本次demo的選擇是對象來處理,以下:java

entry: {
        home: './src/scripts/pages/home/index.js'
        // homecss: './src/styles/pages/home.scss'  // scss入口放到最開始的js中, webpack沒法處理非js文件
    },

輸出(output)

output 位於對象最頂級鍵(key),包括了一組選項,指示 webpack 如何去輸出、以及在哪裏輸出你的「bundle、asset 和其餘你所打包或使用 webpack 載入的任何內容」。

一般而言,經過 output.filename 和 output.path 屬性,來告訴 webpack bundle 的名稱,以及咱們想要生成(emit)到哪裏。demo中的配置如:node

output: {
        path: path.join(__dirname + '/src/dist'),
        // publicPath:'/'
        // publicPath: path.join(__dirname + '/src/dist/'), // 加載外部資源,此選項指定在瀏覽器中所引用的「此輸出目錄對應的公開 URL」
        filename: 'js/[name].js'
    }

須要注意的是,filename: 'js/[name].js'這麼寫是由於webpack支持入口文件爲多個文件時能夠配置不一樣的輸出文件名,參考output-filenamereact

loader

loader 讓 webpack 可以去處理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 能夠將全部類型的文件轉換爲 webpack 可以處理的有效模塊,而後你就能夠利用 webpack 的打包能力,對它們進行處理。本質上,webpack loader 將全部類型的文件,轉換爲應用程序的依賴圖能夠直接引用的模塊。

重要的是要記得,在 webpack 配置中定義 loader 時,要定義在 module.rules 中,而不是 rules。webpack

module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /(node_modules|bower_components)/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env', '@babel/stage-3', '@babel/react']
                    }
                }
            },
            {
                test: /\.scss$/,
                use: extractSass.extract({
                    use: [{
                        loader: "css-loader"
                    }, {
                        loader: "sass-loader"
                    }],
                    // publicPath: './../', // 加載外部資源,把路徑從新定義到dist目錄下,而不是css裏面
                    // use style-loader in development
                    fallback: "style-loader"
                })
            },
            {
                test: /\.(png|svg|jpg|gif|jpeg)$/,
                use: [
                    {   
                        loader: 'file-loader',
                        options: {
                            name: '[name].[ext]',
                            useRelativePath: true, // 圖片相對路徑
                            outputPath: 'images/'
                        }
                    }
                ]
            }
            ]
    }

以上是demo的配置,在 webpack 的配置中 loader 有兩個目標。git

  1. 識別出應該被對應的 loader 進行轉換的那些文件。(使用 test 屬性)
  2. 轉換這些文件,從而使其可以被添加到依賴圖中(而且最終添加到 bundle 中)(use 屬性)

能夠看到,同一個文件能夠順序使用多個loader來加載,每一個loader能夠傳遞參數來進行特殊處理。github

插件(plugins)

插件是 wepback 的支柱功能。webpack 自身也是構建於,你在 webpack 配置中用到的相同的插件系統之上!插件目的在於解決 loader 沒法實現的其餘事。
webpack 插件是一個具備 apply 屬性的 JavaScript 對象。apply 屬性會被 webpack compiler 調用,而且 compiler 對象可在整個編譯生命週期訪問。

因爲插件能夠攜帶參數/選項,你必須在 webpack 配置中,向 plugins 屬性傳入 new 實例。根據你的 webpack 用法,這裏有多種方式使用插件。插件使用插件列表web

demo中使用了兩個pluginsextract-text-webpack-plugin & DefinePlugin,都是按照官方插件文檔配置的。

解析(Resolve)

這些選項能設置模塊如何被解析。webpack 提供合理的默認值,可是仍是可能會修改一些解析的細節。關於 resolver 具體如何工做的更多解釋說明,請查看模塊解析方式。

簡單的說,就是會幫咱們弄好一些默認的選項,好比別名aliasextensions模塊默認後綴、mainFiles默認文件入口等;

resolve: {
        mainFiles: ["index"],
        extensions: ['.js', '.jsx'],
        alias: {
            'stylepages': path.join(__dirname + '/src/styles/pages'),
            'scripts': path.join(__dirname + '/src/scripts/pages'),
            'commonjs': path.join(__dirname + '/src/scripts/common')
        }
    }

遇到問題

關於webpack沒法把css文件做爲入口,須要在js中引入css,而後進行css的分離

關於sass使用@import時來使用alias別名配置的路徑時不被正確解析,sass-loader須要在使用別名的前面加上~,stylelib是別名,使用時@import '~stylelib/base.scss';

關於sass和圖片等外部資源的打包出現的路徑不一致,,有如下幾種方法:

  • 第一種方法,能夠在配置fileloader的時候使用相對路徑:useRelativePath
{
    test: /\.(png|svg|jpg|gif|jpeg)$/,
         use: [
           {   
              loader: 'file-loader',
               options: {
                   name: '[name].[ext]',
                   useRelativePath: true, // 圖片相對路徑
                   outputPath: 'images/'
                 }
              }
          ]
}
  • 第二種方法,在使用ExtractTextWebpackPlugin的時候,能夠根據已有的loader來從新提取loader,在提取新的loader時,能夠配置公共路徑publicPath
const ExtractTextPlugin = require("extract-text-webpack-plugin");

const extractSass = new ExtractTextPlugin({
    filename: "css/[name].css",
    disable: process.env.NODE_ENV === "development"
});


// loader 裏面
{
   test: /\.scss$/,
   use: extractSass.extract({
         use: [{
                loader: "css-loader"
              }, {
                 loader: "sass-loader"
              }],
       publicPath: './../', // 把路徑從新定義到dist目錄下,而不是css裏面
       // use style-loader in development
       fallback: "style-loader"
    })
}
  • 第三種方法,直接在全部的輸出目錄處使用當前的打包路徑,publicPath
output: {
     path: path.join(__dirname + '/src/dist'),
     publicPath:'./'
     // publicPath: path.join(__dirname + '/src/dist/'), // 加載外部資源,此選項指定在瀏覽器中所引用的「此輸出目錄對應的公開 URL」
     filename: 'js/[name].js'
    }

sass

Sass 是一款強化 CSS 的輔助工具,它在 CSS 語法的基礎上增長了變量 (variables)、嵌套 (nested rules)、混合 (mixins)、導入 (inline imports) 等高級功能,這些拓展令 CSS 更增強大與優雅。使用 Sass 以及 Sass 的樣式庫(如 Compass)有助於更好地組織管理樣式文件,以及更高效地開發項目。

使用sass能夠感覺到如下幾點的優點:

  1. 合理的嵌套規則,不須要重複書寫selector。
  2. 變量$、佔位符%均可以很好的提供複用性
  3. 函數、運算能夠很好的增長靈活性

這裏就很少說sass的學習了,能夠查看sass中文sass官網

react

React 是一個採用聲明式,高效並且靈活的用來構建用戶界面的框架。
學習react的重要內容包括:
  1. jsx的書寫語法
  2. 組件Components【props、state、Lifecycle...】
  3. 虛擬dom,
  4. 組件渲染和diff,Lists and Keys

更多的學習react學習官網

redux

Redux 是 JavaScript 狀態容器,提供可預測化的狀態管理。應用中全部的 state 都以一個對象樹的形式儲存在一個單一的 store 中。 唯一改變 state 的辦法是觸發 action,一個描述發生什麼的對象。 爲了描述 action 如何改變 state 樹,你須要編寫 reducers;
  1. 應用中全部的 state 都以一個對象樹的形式儲存在一個單一的 store 中,初始時由reducer初識態來建立
  2. 改變state的惟一方法就是觸發dispatch一個action,
  3. 一個action是本質上一個對象,用來把最新的數據傳到store的有效載荷
  4. Reducer就是把action這個有效載荷解析,並應用到store之中;

具體實踐中:

  1. 書寫reducer,來肯定初始時的state
  2. 根據初始reducer來建立store,並使用store.subscribe來監聽store變化時的操做
  3. 書寫action,來承載每次修改store的變化
  4. 在交互等狀況使用dispatch一個相應的action,
  5. reducer來響應action,並更新store,[store.subscribe監聽函數將會被執行來驅動頁面變化]
import { createStore } from 'redux';

/**
 * 這是一個 reducer,形式爲 (state, action) => state 的純函數。
 * 描述了 action 如何把 state 轉變成下一個 state。
 *
 * state 的形式取決於你,能夠是基本類型、數組、對象、
 * 甚至是 Immutable.js 生成的數據結構。唯一的要點是
 * 當 state 變化時須要返回全新的對象,而不是修改傳入的參數。
 *
 * 下面例子使用 `switch` 語句和字符串來作判斷,但你能夠寫幫助類(helper)
 * 根據不一樣的約定(如方法映射)來判斷,只要適用你的項目便可。
 */
function counter(state = 0, action) {
  switch (action.type) {
  case 'INCREMENT':
    return state + 1;
  case 'DECREMENT':
    return state - 1;
  default:
    return state;
  }
}

// 建立 Redux store 來存放應用的狀態。
// API 是 { subscribe, dispatch, getState }。
let store = createStore(counter);

// 能夠手動訂閱更新,也能夠事件綁定到視圖層。
store.subscribe(() =>
  console.log(store.getState())
);

// 改變內部 state 唯一方法是 dispatch 一個 action。
// action 能夠被序列化,用日記記錄和儲存下來,後期還能夠以回放的方式執行
store.dispatch({ type: 'INCREMENT' });
// 1
store.dispatch({ type: 'INCREMENT' });
// 2
store.dispatch({ type: 'DECREMENT' });
// 1

異步redux

像 redux-thunk 或 redux-promise 這樣支持異步的 middleware 都包裝了 store 的 dispatch() 方法,以此來讓你 dispatch 一些除了 action 之外的其餘內容,例如:函數或者 Promise。

redux-react

Redux 官方提供的 React 綁定庫。 具備高效且靈活的特性。

結合react來完善了下redux的使用,不須要咱們每次都使用store.subscribe來監聽store的變化,提供了新的接口:

<Provider store>
能夠在最頂層將store傳遞至每一個須要store的子組件

connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])
能夠將一些state映射到某個組件,來驅動組件渲染

總結

react-redux-demo

須要webpack3以上

運行方式:

`npm install`  安裝相關依賴
`webpack` 執行webpack來進行打包

在瀏覽器中打開目錄下的/html/pages/home.html文件便可訪問結果

➜  react-redux-demo git:(master) tree -I node_modules 
.
├── html
│   └── pages
│       └── home.html
├── package-lock.json
├── package.json
├── readMe.md
├── src
│   ├── dist
│   │   ├── css
│   │   │   └── home.css

│   │   ├── images
│   │   │   └── head.jpeg
│   │   └── js
│   │       └── home.js
│   ├── scripts
│   │   ├── common
│   │   └── pages
│   │       └── home
│   │           ├── actions
│   │           │   ├── data.js
│   │           │   └── index.js
│   │           ├── components
│   │           │   ├── app.js
│   │           │   ├── article
│   │           │   │   └── index.js
│   │           │   └── consults
│   │           │       └── index.js
│   │           ├── index.js
│   │           ├── reducers
│   │           │   ├── data.js
│   │           │   └── index.js
│   │           └── store
│   │               └── index.js
│   └── styles
│       ├── images
│       │   └── home
│       │       └── head.jpeg
│       ├── lib
│       │   └── base.scss
│       ├── module
│       └── pages
│           └── home.scss
└── webpack.config.js
相關文章
相關標籤/搜索