webpack4+入門使用

  在開始以前檢查node版本,確保node是最新的版本。使用舊版本,你可能遇到各類問題,由於它們可能缺乏 webpack 功能以及/或者缺乏相關 package 包。css

// 檢查node版本
node -v
v8.11.1
mkdir webpack-demo && cd webpack-demo

 

起步

  首先建立一個文件夾webpack4.0-demo,並初始化npm,而後本地安裝webpack和webpack-cli。html

mkdir webpack4.0-demo && cd webpack4.0-demo
// 初始化npm,並所有使用默認值
npm init -y

本地安裝

  使用4+版本須要安裝webpack-cli,node

 cnpm install --save-dev webpack webpack-cli

目錄結構

src/indexwebpack

要在 index.js 中打包 lodash 依賴,咱們須要在本地安裝 library:git

cnpm install --save-dev lodash
import _ from 'lodash'

function creatEl(){
    let el = document.createElement('div');

    // Lodash(目前經過一個 script 腳本引入)對於執行這一行是必需的
    el.innerHTML = _.join(['Hello', 'webpack'], ' ');

    return el
}

document.body.appendChild(creatEl())

dist/index.htmlgithub

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>webpack</title>
</head>
<body>
    <script src="./main.js"></script>
</body>
</html>

package.jsonweb

{
  "name": "webpack4.0-demo",
  "version": "1.0.0",
  "description": "",
  "private": true,  // 刪除入口文件,確保咱們安裝包是
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "lodash": "^4.17.11",
    "webpack": "^4.19.0",
    "webpack-cli": "^3.1.0"
  }
}私有的(private)

  執行webpack或者npx webpack,會將腳本做爲入口文件,而後輸出爲main.js。Node 8.2+ 版本提供的 npx 命令,能夠運行在初始安裝的 webpack 包(package)的 webpack 二進制文件。正則表達式

  在瀏覽器中打開 index.html,若是一切訪問都正常,你應該能看到如下文本:'Hello webpack'。express

使用配置文件

  在 webpack 4 中,能夠無須任何配置使用,然而大多數項目會須要很複雜的設置,這就是爲何 webpack 仍然要支持 配置文件。這比在終端(terminal)中手動輸入大量命令要高效的多,因此讓咱們建立一個取代以上使用 CLI 選項方式的配置文件。npm

  在主目錄先添加一個webpack.config.js文件。

webpack.config.js

const path = require('path');

module.exports = {
    entry: './src/index.js',
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist')
    }
}

package.json

{
  "name": "webpack4.0-demo",
  "version": "1.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"  // 新加代碼
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "lodash": "^4.17.11",
    "webpack": "^4.19.0",
    "webpack-cli": "^3.1.0"
  }
}  

  將index.html中的script標籤的src改爲bundle.js。如今,可使用 npm run build 命令,來替代咱們以前使用的 npx 命令。注意,使用 npm 的 scripts,咱們能夠像使用 npx 那樣經過模塊名引用本地安裝的 npm 包。

管理資源

加載css

  爲了從 JavaScript 模塊中 import 一個 CSS 文件,須要在 module 安裝並添加 style-loader 和 css-loader。

cnpm install --save-dev css-loader style-loader

webpack.config.js

const path = require('path');

module.exports = {
    entry: './src/index.js',
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    'style-loader',
                    'css-loader'
                ]
            }
        ]
    }
}
webpack 根據正則表達式,來肯定應該查找哪些文件,並將其提供給指定的 loader。在這種狀況下,以 .css 結尾的所有文件,都將被提供給style-loader和css-loader。
這使你能夠在依賴於此樣式的文件中 import 'style.css'。如今,當該模塊運行時,含有 CSS 字符串的 <style> 標籤,將被插入到 html 文件的<head>中。

在src文件夾下添加一個style.css文件

src/style.css

.hello{
    color: red;
}

src/index.js

import _ from 'lodash'
import './style.css'
function creatEl(){
    let el = document.createElement('div');

    // Lodash(目前經過一個 script 腳本引入)對於執行這一行是必需的
    el.innerHTML = _.join(['Hello', 'webpack'], ' ');

    el.className = 'hello';

    return el
}

document.body.appendChild(creatEl())

   從新執行命令,在瀏覽器中打開index.html能夠看到字體變成紅色。

加載圖片

  加載圖片須要先安裝file-loader

cnpm install --save-dev file-loader

webpack.config.js

const path = require('path');

module.exports = {
    entry: './src/index.js',
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    'style-loader',
                    'css-loader'
                ]
            },
            { test: /\.(jpg|png|svg|gif)$/,
                use: [
                    'file-loader' ] }
        ]
    }
}

src/index.js

import _ from 'lodash'

import "./style.css"
import Icon from './01.png'

function creatEl(){
    let el = document.createElement('div');

    // Lodash(目前經過一個 script 腳本引入)對於執行這一行是必需的
    el.innerHTML = _.join(['Hello', 'webpack'], ' ');

    el.className = 'hello';

    let img = new Image();
    img.src = Icon
    el.appendChild(img)
    return el
}

document.body.appendChild(creatEl())

 加載字體

  file-loader 和 url-loader 能夠接收並加載任何文件,而後將其輸出到構建目錄。這就是說,咱們能夠將它們用於任何類型的文件,包括字體。讓咱們更新 webpack.config.js 來處理字體文件:

webpack.config.js

const path = require('path');

module.exports = {
    entry: './src/index.js',
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    'style-loader',
                    'css-loader'
                ]
            },
            {
                test: /\.(jpg|png|svg|gif)$/,
                use: [
                    'file-loader'
                ]
            },
            { test: /\.(woff|woff2|eot|ttf|otf)/,
                use: [
                    'file-loader' ] }
        ]
    }
}

 輸出管理

  到目前爲止,咱們在index.html文件中手動引入全部資源,然而隨着應用程序增加,而且一旦對文件名使用哈希並輸出多個bundle,手動的對index.HTML文件進行管理,一切就會變得困難起來。然而,咱們能夠經過使用一些插件,會使這個過程變得更容易操控。

  首先,要在src文件夾下新增一個print.js文件。

 

src/print.js

export default function print(){
    console.log('hello webpack')
}

src/index.js

import _ from 'lodash'

import "./style.css"
import Icon from './01.png'
import print from './print' function creatEl(){ let el = document.createElement('div'); // Lodash(目前經過一個 script 腳本引入)對於執行這一行是必需的 el.innerHTML = _.join(['Hello', 'webpack'], ' '); el.className = 'hello';
let btn
= document.createElement('button'); btn.innerHTML = 'click me' btn.onclick = print;
let img
= new Image(); img.src = Icon el.appendChild(img) el.appendChild(btn) return el } document.body.appendChild(creatEl())

webpack.config.js

  安裝 html-webpack-plugin 插件。

cnpm install --save-dev html-webpack-plugin

調整webpack.config.js文件

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

module.exports = {
    devtool: 'source-map',
    entry: {
        app: './src/index.js',
     print: './src/print.js' }, output: { filename: '[name].bundle.js', path: path.resolve(__dirname, 'dist') }, module: { rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] }, { test: /\.(jpg|png|svg|gif)$/, use: [ 'file-loader' ] }, { test: /\.(woff|woff2|eot|ttf|otf)/, use: [ 'file-loader' ] } ] }, plugins: [ new HtmlWebpackPlugin({ title: 'webpack',   // 生成的HTML文件的標題 template: path.resolve(__dirname, 'index.html')  // 使用的模板路徑 }) ] }

   運行程序能夠看到build文件夾下會生成一個index.html文件。全部的bundle文件都會被引入到index文件中。

清楚dist文件夾

  因爲常常修改,dist文件夾下會變得很是混亂webpack 會生成文件,而後將這些文件放置在 /dist 文件夾中,可是 webpack 沒法追蹤到哪些文件是實際在項目中用到的。一般,在每次構建前清理 /dist 文件夾,是比較推薦的作法,所以只會生成用到的文件。

  首先安裝插件:

cnpm install clean-webpack-plugin --save-dev
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
    devtool: 'source-map',
    entry: {
        app: './src/index.js',
     print: './src/print.js' }, output: { filename: '[name].bundle.js', path: path.resolve(__dirname, 'dist') }, module: { rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] }, { test: /\.(jpg|png|svg|gif)$/, use: [ 'file-loader' ] }, { test: /\.(woff|woff2|eot|ttf|otf)/, use: [ 'file-loader' ] } ] }, plugins: [ new CleanWebpackPlugin(['dist']), new HtmlWebpackPlugin({ // 用於生成的HTML文檔的標題 title: 'webpack', // 使用的模板路徑 template: path.resolve(__dirname, 'index.html') }) ] }

運行程序會看到先刪除dist文件夾,而後會再次生成。

錯誤追蹤

  在使用webpack打包源代碼時,會很難追蹤到錯誤和警告在源代碼中的原始位置。好比,將三個源文件(a.js、b.js和c.js)打包到一個bundle中,而其中一個源文件包含一個錯誤,那麼堆棧跟蹤就會簡單的指向bundle.js。爲了更容易的追蹤錯誤和警告,咱們可使用source map功能,將編譯後的代碼映射回原始源代碼。

webpack.config.js

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

module.exports = {
    devtool: 'source-map',
    entry: {
        app: './src/index.js',
     print: './src/print.js' }, output: { filename: '[name].bundle.js', path: path.resolve(__dirname, 'dist') }, module: { rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] }, { test: /\.(jpg|png|svg|gif)$/, use: [ 'file-loader' ] }, { test: /\.(woff|woff2|eot|ttf|otf)/, use: [ 'file-loader' ] } ] }, plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ // 用於生成的HTML文檔的標題 title: 'webpack', // 使用的模板路徑 template: path.resolve(__dirname, 'index.html') }) ] }

src/print.js

export default function print(){
    console.log('hello webpack');
    console.error('error');
}

點擊按鈕能夠看到

更多詳細內容,查看devtool

模塊熱更新

  每次編譯代碼都要手動執行一次npm run build,這樣變得很麻煩。webpack中有不一樣幾個選項,能夠在代碼發生變化時自動編譯代碼:

  1. webpack's Watch Mode
  2. webpack-dev-server
  3. webpack-dev-middleware

可是在大多數場景中使用的是webpack-dev-server。

觀察者模式

添加一個用於啓動 webpack 的觀察模式的 npm script 腳本:

package.json

{
  "name": "webpack4.0-demo",
  "version": "1.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "watch": "webpack --watch",
    "build": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "clean-webpack-plugin": "^0.1.19",
    "css-loader": "^1.0.0",
    "express": "^4.16.3",
    "file-loader": "^2.0.0",
    "html-webpack-plugin": "^3.2.0",
    "lodash": "^4.17.11",
    "style-loader": "^0.23.0",
    "webpack": "^4.19.0",
    "webpack-cli": "^3.1.0"
  }
}

  如今,運行npm run watch,就會看到webpack編譯代碼後並不會退出。這是由於 script 腳本還在觀察文件。如今,webpack 觀察文件的同時,咱們先移除咱們以前引入的錯誤:

src/print.js

export default function print(){
    console.log('hello webpack');
    console.log('hello world');
}

而後刷新頁面,能夠看到:

惟一的缺點是,爲了看到修改後的實際效果,你須要刷新瀏覽器。若是可以自動刷新瀏覽器就更好了,能夠嘗試使用 webpack-dev-server,剛好能夠實現咱們想要的功能。

webpack-dev-server

webpack-dev-server 爲你提供了一個簡單的 web 服務器,而且可以實時從新加載(live reloading)。首先要安裝插件

cnpm install --save-dev webpack-dev-server

webpack.config.js

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

module.exports = {
    devtool: 'source-map',
    entry: {
        app: './src/index.js',
        print: './src/print.js'
    },
    output: {
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    'style-loader',
                    'css-loader'
                ]
            },
            {
                test: /\.(jpg|png|svg|gif)$/,
                use: [
                    'file-loader'
                ]
            },
            {
                test: /\.(woff|woff2|eot|ttf|otf)/,
                use: [
                    'file-loader'
                ]
            }
        ]
    },
    plugins: [
        new CleanWebpackPlugin(['dist']),
        new HtmlWebpackPlugin({
            // 用於生成的HTML文檔的標題
            title: 'webpack',
            // 使用的模板路徑
            template: path.resolve(__dirname, 'index.html')
        })
    ],
    devServer: { contentBase: path.join(__dirname, 'dist') }
}

以上配置告知 webpack-dev-server,在 localhost:8080 下創建服務,將 dist目錄下的文件,做爲可訪問文件。添加一個 script 腳本,能夠直接運行開發服務器(dev server):

package.json

{
  "name": "webpack4.0-demo",
  "version": "1.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "watch": "webpack --watch",
    "start": "webpack-dev-server --open","build": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "clean-webpack-plugin": "^0.1.19",
    "css-loader": "^1.0.0",
    "express": "^4.16.3",
    "file-loader": "^2.0.0",
    "html-webpack-plugin": "^3.2.0",
    "lodash": "^4.17.11",
    "style-loader": "^0.23.0",
    "webpack": "^4.19.0",
    "webpack-cli": "^3.1.0",
    "webpack-dev-middleware": "^3.3.0",
    "webpack-dev-server": "^3.1.8"
  }
}

如今,咱們能夠在命令行中運行 npm start,就會看到瀏覽器自動加載頁面。若是如今修改和保存任意源文件,web 服務器就會自動從新加載編譯後的代碼。

webpack-dev-middleware

  webpack-dev-middleware 是一個容器(wrapper),它能夠把 webpack 處理後的文件傳遞給一個服務器(server)。 webpack-dev-server 在內部使用了它,同時,它也能夠做爲一個單獨的包來使用,以便進行更多自定義設置來實現更多的需求。接下來是一個 webpack-dev-middleware 配合 express server 的示例。

首先安裝插件

cnpm install --save-dev express webpack-dev-middleware

接下來咱們須要對 webpack 的配置文件作一些調整,以確保中間件(middleware)功能可以正確啓用:

webpack.config.js

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

module.exports = {
    devtool: 'source-map',
    entry: {
        app: './src/index.js',
        print: './src/print.js'
    },
    output: {
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist'),
        publicPath: '/'
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    'style-loader',
                    'css-loader'
                ]
            },
            {
                test: /\.(jpg|png|svg|gif)$/,
                use: [
                    'file-loader'
                ]
            },
            {
                test: /\.(woff|woff2|eot|ttf|otf)/,
                use: [
                    'file-loader'
                ]
            }
        ]
    },
    plugins: [
        new CleanWebpackPlugin(['dist']),
        new HtmlWebpackPlugin({
            // 用於生成的HTML文檔的標題
            title: 'webpack',
            // 使用的模板路徑
            template: path.resolve(__dirname, 'index.html')
        })
    ],
    devServer: {
        contentBase: path.join(__dirname, 'dist')
    }
}

publicPath 也會在服務器腳本用到,以確保文件資源可以在 http://localhost:3000 下正確訪問。而後在項目根目錄下添加 server.js 文件,下一步就是設置咱們自定義的 express 服務:

server.js

const express = require('express');
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');

const app = express();
const config = require('./webpack.config.js');
const complier = webpack(config);

app.use(webpackDevMiddleware(complier, {
    publicPath: config.output.publicPath
}));

app.listen(3000, function(){
    console.log('server is running')
})

package.json

{
  "name": "webpack4.0-demo",
  "version": "1.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "watch": "webpack --watch",
    "start": "webpack-dev-server --open",
    "server": "node server.js",
    "build": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "clean-webpack-plugin": "^0.1.19",
    "css-loader": "^1.0.0",
    "express": "^4.16.3",
    "file-loader": "^2.0.0",
    "html-webpack-plugin": "^3.2.0",
    "lodash": "^4.17.11",
    "style-loader": "^0.23.0",
    "webpack": "^4.19.0",
    "webpack-cli": "^3.1.0",
    "webpack-dev-middleware": "^3.3.0",
    "webpack-dev-server": "^3.1.8"
  }
}

如今,在你的終端執行 npm run server,而後打開瀏覽器跳轉到http://localhost:3000,將會看到webpack程序已經運行。

模塊熱替換

  模塊熱替換(Hot Module Replacement 或 HMR)是 webpack 提供的最有用的功能之一。它容許在運行時更新各類模塊,而無需進行徹底刷新。

啓用HMR

  啓用此功能實際上至關簡單。而咱們要作的,就是更新 webpack-dev-server 的配置,和使用 webpack 內置的 HMR 插件。咱們還要刪除掉 print.js 的入口起點,由於它如今正被 index.js 模式使用。

webpack.config.js

 

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

module.exports = {
    devtool: 'source-map',
    entry: {
        app: './src/index.js'
    },
    output: {
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist'),
        publicPath: '/'
    },
    plugins: [
        new CleanWebpackPlugin(['dist']),
        new HtmlWebpackPlugin({
            // 用於生成的HTML文檔的標題
            title: 'webpack',
            // 使用的模板路徑
            template: path.resolve(__dirname, 'index.html')
        }),
        new webpack.NamedModulesPlugin(),
        new webpack.HotModuleReplacementPlugin()
    ],
    devServer: {
        contentBase: path.join(__dirname, 'dist'),
        hot: true
    }
}

 

  注意,咱們還添加了 NamedModulesPlugin,以便更容易查看要修補(patch)的依賴。在起步階段,咱們將經過在命令行中運行 npm start 來啓動並運行 dev server。如今,咱們來修改 index.js 文件,以便當 print.js 內部發生變動時能夠告訴 webpack 接受更新的模塊

 

index.js

 

import _ from 'lodash'

import print from './print'

function creatEl(){
    let el = document.createElement('div');

    // Lodash(目前經過一個 script 腳本引入)對於執行這一行是必需的
    el.innerHTML = _.join(['Hello', 'webpack'], ' ');

    el.className = 'hello';

    let btn = document.createElement('button');
    btn.innerHTML = 'click me'
    btn.onclick = print;
    el.appendChild(btn)
    return el
}

document.body.appendChild(creatEl())

if (module.hot) {
    module.hot.accept('./print.js', function(){
        console.log('Accepting the updated printMe module!');
        print();
    })
}

如需查看webpack更多配置詳情,前往webpack配置

相關文章
相關標籤/搜索