webpack入門指南

demo地址:https://github.com/yonglijia/...javascript

首先來介紹下webpack是幹嗎的。 css

webpack簡單的來說,是一個前端模塊化管理和打包工具,能夠將你的文件所依賴的js,css,node包等所有打包成一個bundle文件,而且可以處理各類模塊之間依賴問題。在webpack的世界裏,一切皆模塊!但它又不只僅是一個打包工具。它不只可以輕鬆處理你項目中的依賴關係和加載順序,還能讓這個流程更加智能化,自動化。html

webpack的使用,最複雜的一部分是莫過於它的配置項。webpack經過你的配置項,放置全部與打包相關的信息。一個基本的配置包括前端

module.exports = {
        entry: '',
        output: {},
        module: {
            rules: []
        },
        plugins: [],
};

咱們能夠這樣理解這幾個配置:java

你若是要打包一個文件,那首先要指定文件的地址,也就是entry;打包以後放在那裏呢,也就是output;打包過程當中文件要通過怎麼樣的處理,也就是rules中的loader;如何可以使webpack打包更快,體積更小呢,也就是plugins。這些配置相輔相成,緊密結合node

這些配置命名須要寫入webpack.config.js中。在項目中,執行webpack,就會自動引用這個文件。react

下面咱們詳細介紹下這些配置。創建一個簡單的項目,包含webpack

1.jpg

testWebpck.jsgit

module.exports = function() {
    var testDiv = document.createElement('div');
    testDiv.textContent = "hello world";
    return testDiv;
};

index.jsgithub

var testWebpack = require('./testWebpack.js');
document.querySelector("#root").appendChild(testWebpack());

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>learn webpack</title>
</head>
<body>
<div id="root">

</div>
<script src="build/bundle.js"></script>
</body>
</html>

webpack.config.js

module.exports = {
    entry: __dirname+"/app/index.js",//打包的js
    output: {
        path: __dirname + "/build",//打包後的文件存放的地方
        filename: "bundle.js",//打包後bundle文件的文件名
    },
    module: {
        rules: []
    },
    plugins: [],
};

咱們在項目根目錄中,執行webpack

2.jpg

瀏覽器打開index.html,能夠看到hello world!。修改testWebpck, 修改成「hello webpack!」,從新執行webpack,再次打開index.html,能夠看到瀏覽器中變爲hello webpack!

開發環境

咱們可使用webpack-dev-server,來構建一個本地服務器,經過這個服務器,監聽你的代碼,實時更新你修改的內容。

首先

npm install webpack-dev-server

而後在package.json中添加腳本

"scripts": {
    "start": "webpack-dev-server --config webpack.config.js",
 },

npm的start命令是一個特殊的腳本,直接使用npm start就能夠執行其對於的命令;而若是不是start,想要在命令行中運行時,須要這樣用npm run {script name}npm run build

執行npm start,在瀏覽器中輸入http://127.0.0.1:8080,能夠看到咱們所看到的如出一轍的頁面。

Webpac-dev-server須要添加devServer配置

devServer{
  hot:true,//
  inline:true,//
  port:8080,//默認8080
  proxy:{//接口代理
    '/xxx/**': {//接口匹配的地址
                target:"代理地址",
                secure: false
            },
  }
}

目前爲止,咱們已經使用wepack成功完成了一個文件的打包,而且能在開發環境中使用。可是未使用任何的loader,plugin,由於這裏面涉及到的文件還太少,種類也很少。下面來一步步豐富這個小項目,引入所須要的配置。

咱們在項目中引入css

index.css

#root{
    border:1px solid red;
}

在index.js中引入require('./index.css');

執行npm start

7.jpg
這時已經報錯,提示咱們要引入相應的loader來處理css。是時候展現真正的技術了——— loader。

loader

loader是什麼呢?正如咱們上面所講的是,它用來如何處理咱們的打包文件的;如今若是不引入loader,那就沒法處理css文件。loader不只僅是處理css,還能夠用來css的預處理、js的中使用ES6等高級語法處理成瀏覽器能兼容的格式。文件、圖片、json等處理,都須要用到loader;通過loader的處理,這些文件可以很好的打入打包後的bundle中。

一個loader所須要的配置包括四個方面

test、loader、includer/exclude、query

首先來看個示範

{
    test: /\.js$|\.jsx$/,
    loader: 'babel-loader',
    exclude: /(node_modules|bower_components)/,
    query: {
            presets: ['es2015', 'react'],
            plugins: ['transform-class-properties', 'lodash']
    },
},

test是一個正則表達式,它用來匹配適用於loader文件的擴展名

loader中是loader的名稱,1.x版本不須要加上「-loader」,日後的版本須要加上「-loader」.

這兩個都是必須添加的配置,下面兩個是可選的。

include/exclude:手動添加必須處理的文件(文件夾)或屏蔽不須要處理的文件(文件夾)

query:爲loaders提供額外的設置

CSS - loader

那咱們來根據上面的配置來設置loader,來處理css。

webpack提供兩個工具處理樣式表,css-loader 和 style-loader;安裝這兩個npm包,修改咱們的配置

module.exports = {
    entry: __dirname+"/app/index.js",//打包的js
    output: {
        path: __dirname + "/build",//打包後的文件存放的地方
        filename: "bundle.js",//打包後bundle文件的文件名
    },
    module: {
        rules: [ {test: /\.css$/, loaders: ["style-loader", "css-loader"]},]//引入多個loader,loader要寫成loaders,屬性爲一個數組,存放各個loader
    },
    plugins: [],
};

執行npm start,在瀏覽器中咱們發現,helllo world中已經添加上了紅色的邊框了。

css-loader使你可以使用相似@import和url(...)的方法實現require的功能,style-loader將全部的計算後的樣式加入頁面中,兩者組合在一塊兒使你可以把樣式表嵌入webpack打包後的js文件中

有一點要注意的是:loader是有順序的。webpack確定是先將全部css模塊依賴解析完獲得計算結果再建立style標籤。所以應該把style-loader放在css-loader的前面(webpack loader的執行順序是從右到左),順序不對,會報錯。

這樣咱們基本上使用了完成了一個loader的基本配置。

咱們來配置下添加其餘loader的配置項:

  • 處理圖片

須要同時安裝url-loader和file-loader

{test: /\.(?:jpg|gif|png)$/, loader: 'url-loader?limit=10240&name=images/[name]-[hash:10].[ext]'},

url-loader與file-loader的工做方式類似,若是文件的體積比byte limit小,就能返回Data Url。若是圖片比limit小,將直接以base64的形式內聯在代碼中。若是圖片比limit(以bytes爲單位)大,那麼webpack就會使用file-loader去處理文件,而且全部的查詢參數都會傳遞給file-loader。

咱們想把js和圖片打包成不一樣的文件夾,須要把output配置項修改一下

output: {
        path: __dirname + "/build",//打包後的文件存放的地方
        filename: "js/bundle.js",//打包後bundle文件的文件名
    },

在項目app文件夾中分別添加兩個圖片,一個大於1024,一個小於1024,circle_loaction.png,data_update.gif

添加上面的配置,執行weibpack,發現一個有一個文件在build/images中生成。

4.png

這裏面有一個路徑的點須要注意:

若是在output中添加publicPath,好比說/xxx/

module.exports = {
    entry: __dirname+"/app/index.js",//打包的js
    output: {
          publicPath: '/xxx/',
        path: __dirname + "/build",//打包後的文件存放的地方
        filename: "bundle.js",//打包後bundle文件的文件名
    },
    module: {
        rules: [
          {test: /\.css$/, loaders: ["style-loader", "css-loader"]},
          {test: /\.(?:jpg|gif|png)$/, loader: 'url-loader?limit=10240&name=images/[name]-[hash:10].[ext]'},
        ]
    },
    plugins: [],
};

那咱們訪問http://127.0.0.1:8080,發現bundle找不到。這是由於加上publicPath以後,訪問內存中的文件bundle都須要加上/xxx/(但實際上引用的是內存中的文件,既不是/build/js/也不是/xxx/)。因此要修改html中的引用地址方能使用。

<script src="xxx/js/bundle.js"></script>

publicPath表示資源的發佈地址,加上該屬性後,打包文件中全部經過相對路徑引用的資源都會被配置的路徑所替換。

若是此時修改index.css

#root{
    border:1px solid red;
    height: 350px;
    background-image:url("./data_update.gif");
}

./data_update.gif 就會自動替換成xxx/images/data_update-37a1914078.gif。

path和publicPath的區別

path:/build/js

publicPaht:/online/

  • 線下環境

path是打包後文件存放的路徑,不能用於html中的js引用

publicPath表示的是資源發佈的路徑。自動指向path編譯目錄(/online/ => /build/js/),html中引用js文件時,必須引用此虛擬路徑。

  • 線上環境

webpack進行編譯(固然是編譯到/build/js/),咱們須要把目錄(/build/js/)下的文件,所有複製到/online/目錄下(注意:不是去修改index.html中引用bundle.js的路徑)

  • 處理jsx文件

webpack不能直接處理jsx,須要藉助於babel.
babel堪稱神器,被譽爲下一代 JavaScript 語法的編譯器。用它,你能夠不用等瀏覽器的支持,就可使用最新的標準的語法。使用它能夠解析jsx的語法。對於babel,不作過多介紹。

首先安裝

npm install --save-dev babel-cli babel-preset-env babel-core babel-loader babel-preset-es2015 babel-preset-react react react-dom

建立 .babelrc

{
  "presets": ["react","es2015"]
}

添加loader

{
     test: /\.js$|\.jsx$/,
     exclude: /(node_modules|bower_components)/,
     loader: 'babel-loader',
}

修改index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>learn webpack</title>
</head>
<body>
    <div id="root">

    </div>
    <div id="react">

    </div>
    <script src="build/js/index.js"></script>
    <script src="build/js/testReact.js"></script>
</body>
</html>

添加testWebpack.jsx,

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

class TestReact extends React.Component{
    constructor(props){
        super(props);
    }
    render(){
        return <div>this is a react div
            <img src={require('./data_update.gif')}/>
        </div>
    }
}
ReactDOM.render(<TestReact/>,document.getElementById('react'))

修改配置

module.exports = {
    entry: {
        index :__dirname+"/app/index.js",
        testReact:__dirname+"/app/testReact.jsx",
    },
    output: {
        path: __dirname + "/build",//打包後的文件存放的地方
        filename: "js/[name].js"//打包後輸出文件的文件名
    },
    module: {
        rules: [
            {test: /\.css$/, loaders: ["style-loader", "css-loader"]},
            {test: /\.(?:jpg|gif|png)$/, loader: 'url-loader?limit=10240&name=images/[name]-[hash:10].[ext]'},
            {
                test: /\.js$|\.jsx$/,
                exclude: /(node_modules|bower_components)/,
                loader: 'babel-loader',
            }
        ]
    },
    plugins: [],
};

這裏咱們設置了兩個入口文件,而且打包成不一樣的js,這個js的名字和他們自己的js的名字相同,經過filename: "js/[name].js"指定。

7.jpg

這樣設置完咱們就完成了使用babel-loader處理jsx文件。

稍微展開一點entry:

entry 有三種類型字符串,數組和對象

  1. entry:"xxx/index.js",

  2. entry:["xxx/index.js","xxx/index2.js"],

  3. entry:{
    index:"xxx/index.js",
    index2:"xxx/index2.js"
    },

plugin

下面咱們介紹下,如何添加插件,使咱們的打包工程更快,更智能。

先介紹下一些經常使用的插件。

  • uglifyjs-webpack-plugin :JS壓縮

var webpack = require('webpack');
var UglifyJSPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
    entry: {
        index :__dirname+"/app/index.js",
        testReact:__dirname+"/app/testReact.jsx",
    },
    output: {
        path: __dirname + "/build",//打包後的文件存放的地方
        filename: "js/[name].js"//打包後輸出文件的文件名
    },
    module: {
        rules: [
            {test: /\.css$/, loaders: ["style-loader", "css-loader"]},
            {test: /\.(?:jpg|gif|png)$/, loader: 'url-loader?limit=10240&name=images/[name]-[hash:10].[ext]'},
            {
                test: /\.js$|\.jsx$/,
                exclude: /(node_modules|bower_components)/,
                loader: 'babel-loader',
            }
        ]
    },
    plugins: [
      new UglifyJSPlugin(),
    ],
};

咱們這時候打開build/js中的js文件,發現裏面都被壓縮混淆了。

  • DefinePlugin:定義全局變量

  • Hot Module Replacement:

    在webpack中實現HMR很簡單,只須要兩個配置

    1. 添加new webpack.HotModuleReplacementPlugin()

    2. 修改腳本 "start": "webpack-dev-server --config webpack.config.js",

插件分爲內置和外置的,不過用法都是大同小異的。不一樣的插件,配置參數也不同。

其餘配置

  • devtool:這個是用來配置soucemap的類型,在開發的時候調試特別有用。裏面的配置特別多,後面會單獨介紹這個地方。

  • resolve:配置短路徑引用

    resolve: {
            alias: {
                module: path.resolve(APP_PATH, 'module'),
                component: path.resolve(APP_PATH, "component"),
                service: path.resolve(APP_PATH, "service"),
                page: path.resolve(APP_PATH, "page"),
                node_modules: path.resolve(ROOT_PATH, 'node_modules')
            },
            extensions: ['.js', '.jsx', '.json', '.scss']
        },

    使用這個選項的話,你能夠直接使用好比require('page/index'),其實就是path.resolve(APP_PATH, "page")+'/index',extensions是用來匹配所要引用的文件類型,匹配以index開頭的 ['.js', '.jsx', '.json', '.scss']文件,若是沒有,就會報錯。

這篇文章權當個入門文檔,裏面還有不少須要一一深刻挖掘的,好比devtool到底選擇哪一個最好,怎麼使項目的打包更快,怎麼使用dll等等,後續會一點一點的寫。

相關文章
相關標籤/搜索