您的当前位置:首页正文

webpack学习配置笔记(一)

来源:华拓网

安装webpack

本地安装

npm install --save-dev webpack
npm install --save-dev webpack@<version>

对于大多数项目,我们建议本地安装。这可以使我们在引入破坏式变更(breaking change)的依赖时,更容易分别升级项目。通常,webpack 通过运行一个或多个 npm scripts,会在本地 node_modules 目录中查找安装的 webpack:

"scripts":{
    "start":"webpack --config webpack.config.js"
}

全局安装

npm install --global webpack

最新体验版本

npm install webpack@beta
npm install webpack/webpack

安装这些最新体验版本时要小心!它们可能仍然包含 bug,因此不应该用于生产环境。

起步

创建目录,初始化npm ,和在本地安装webpack

mkdir webpack-demo && cd webpack-demo
npm init -y
npm install --save-dev webpack

Lodash

有多年开发经验的工程师,往往都会有自己的一套工具库,称为 utils、helpers 等等,这套库一方面是自己的技术积累,另一方面也是对某项技术的扩展,领先于技术规范的制定和实现。

Lodash 就是这样的一套工具库,它内部封装了诸多对字符串、数组、对象等常见数据类型的处理函数,其中部分是目前 ECMAScript 尚未制定的规范,但同时被业界所认可的辅助函数。目前每天使用 npm 安装 Lodash 的数量在百万级以上,这在一定程度上证明了其代码的健壮性,值得我们在项目中一试。

安装

npm install --save lodash

管理资源

加载css

为了从 JavaScript 模块中 import 一个 CSS 文件,你需要在 module 配置中 安装并添加 style-loader 和 css-loader:

npm install --save-dev style-loader css-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'
                ]
            }
        ]
    }
};

现在我们可以使用import './style.css'这种代码了。

加载图片

假想,现在我们正在下载 CSS,但是我们的背景和图标这些图片,要如何处理呢?使用 file-loader,我们可以轻松地将这些内容混合到 CSS 中:

npm 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: /\.(png|svg|jpg|gif)$/,
+         use: [
+           'file-loader'
+         ]
+       }
      ]
    }
  };

加载字体

那么,像字体这样的其他资源如何处理呢?file-loader 和 url-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: /\.(png|svg|jpg|gif)$/,
          use: [
            'file-loader'
          ]
        },
+       {
+         test: /\.(woff|woff2|eot|ttf|otf)$/,
+         use: [
+           'file-loader'
+         ]
+       }
      ]
    }
  };

加载数据

npm install --save-dev csv-loader xml-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: /\.(png|svg|jpg|gif)$/,
          use: [
            'file-loader'
          ]
        },
        {
          test: /\.(woff|woff2|eot|ttf|otf)$/,
          use: [
            'file-loader'
          ]
        },
+       {
+         test: /\.(csv|tsv)$/,
+         use: [
+           'csv-loader'
+         ]
+       },
+       {
+         test: /\.xml$/,
+         use: [
+           'xml-loader'
+         ]
+       }
      ]
    }
  };

管理输出

webpack.config.js

const path = require('path');

module.exports = {
    // entry: './src/index.js',
    entry:{
        app:'./src/index.js',
        print:'./src/print.js'
    },
    output: {
        // filename: 'bundle.js',
        filename:'[name].bundle.js',
        path: path.resolve(__dirname, 'dist')
    }
    ...
};

执行npm run build后,我们可以看到

Hash: 1e971c5b5f7389f57299
Version: webpack 3.9.1
Time: 785ms
          Asset     Size  Chunks                    Chunk Names
  app.bundle.js   561 kB    0, 1  [emitted]  [big]  app
print.bundle.js  2.74 kB       1  [emitted]         print
   [0] ./src/print.js 85 bytes {0} {1} [built]
   [1] ./src/index.js 430 bytes {0} [built]
   [3] (webpack)/buildin/global.js 509 bytes {0} [built]
   [4] (webpack)/buildin/module.js 517 bytes {0} [built]
   [5] ./src/style.css 1.04 kB {0} [built]
   [6] ./node_modules/.0.28.7@css-loader!./src/style.css 198 bytes {0} [built]
    + 4 hidden modules

我们可以看到,webpack 生成 print.bundle.js 和 app.bundle.js 文件,这也和我们在 index.html 文件中指定的文件名称相对应。如果你在浏览器中打开 index.html,就可以看到在点击按钮时会发生什么。

设定HtmlWebpackPlugin

安装

npm install --save-dev 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 = {
    // entry: './src/index.js',
    entry:{
        app:'./src/index.js',
        print:'./src/print.js'
    },
    output: {
        // filename: 'bundle.js',
        filename:'[name].bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    module:{
        ...
    },
    plugins:[
        new HtmlWebpackPlugin({
            title:'Output Management'
        })
    ]
};

在我们构建之前,你应该了解,虽然在 dist/ 文件夹我们已经有 index.html 这个文件,然而 HtmlWebpackPlugin 还是会默认生成 index.html 文件。这就是说,它会用新生成的 index.html 文件,把我们的原来的替换。让我们看下在执行 npm run build 后会发生什么:

Hash: f6192796510782b20e6c
Version: webpack 3.9.1
Time: 1028ms
          Asset       Size  Chunks                    Chunk Names
  app.bundle.js     561 kB    0, 1  [emitted]  [big]  app
print.bundle.js    2.74 kB       1  [emitted]         print
     index.html  254 bytes          [emitted]         
   [0] ./src/print.js 85 bytes {0} {1} [built]
   [1] ./src/index.js 430 bytes {0} [built]
   [3] (webpack)/buildin/global.js 509 bytes {0} [built]
   [4] (webpack)/buildin/module.js 517 bytes {0} [built]
   [5] ./src/style.css 1.04 kB {0} [built]
   [6] ./node_modules/.0.28.7@css-loader!./src/style.css 198 bytes {0} [built]
    + 4 hidden modules
Child html-webpack-plugin for "index.html":
     1 asset
       [2] (webpack)/buildin/global.js 509 bytes {0} [built]
       [3] (webpack)/buildin/module.js 517 bytes {0} [built]
        + 2 hidden modules

如果你在代码编辑器中将 index.html 打开,你就会看到 HtmlWebpackPlugin 创建了一个全新的文件,所有的 bundle 会自动添加到 html 中。

如果你想要了解更多 HtmlWebpackPlugin 插件提供的全部功能和选项,那么你就应该多多熟悉 HtmlWebpackPlugin 仓库。

清理/dist文件夹

你可能已经注意到,由于过去的指南和代码示例遗留下来,导致我们的 /dist 文件夹相当杂乱。webpack 会生成文件,然后将这些文件放置在 /dist 文件夹中,但是 webpack 无法追踪到哪些文件是实际在项目中用到的。

通常,在每次构建前清理 /dist 文件夹,是比较推荐的做法,因此只会生成用到的文件。让我们完成这个需求。

npm isntall clean-webpack-plugin --save-dev
cnpm isntall clean-webpack-plugin --save-dev

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
    // entry: './src/index.js',
    entry:{
        app:'./src/index.js',
        print:'./src/print.js'
    },
    output: {
        // filename: 'bundle.js',
        filename:'[name].bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    module:{
        rules:[
            ...
        ]
    },
    plugins:[
        new CleanWebpackPlugin(['dist']),//清理的文件夹
        new HtmlWebpackPlugin({
            title:'Output Management'
        })
    ]
};

Manifest

你可能会感兴趣,webpack及其插件似乎“知道”应该哪些文件生成。答案是,通过 manifest,webpack 能够对「你的模块映射到输出 bundle 的过程」保持追踪。如果你对通过其他方式来管理 webpack 的输出更感兴趣,那么首先了解 manifest 是个好的开始。

开发

在这里我们学习如何搭建一个开发环境,让我们的开发更容易一些。

使用source map

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
    // entry: './src/index.js',
    entry:{
        app:'./src/index.js',
        print:'./src/print.js'
    },
    output: {
        // filename: 'bundle.js',
        filename:'[name].bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    module:{
        rules:[
            ...
        ]
    },
    plugins:[
        new CleanWebpackPlugin(['dist']),//清理的文件夹
        new HtmlWebpackPlugin({
            title:'Output Management'
        })
    ],
    devtool:'inline-source-map'
};

添加devtool:'inline-source-map'

选择一个开发工具

每次要编译代码时,手动运行 npm run build 就会变得很麻烦。

webpack 中有几个不同的选项,可以帮助你在代码发生变化后自动编译代码:

webpack's Watch Mode
webpack-dev-server
webpack-dev-middleware
多数场景中,你可能需要使用 webpack-dev-server,但是不妨探讨一下以上的所有选项。

使用观察模式

你可以指示 webpack "watch" 依赖图中的所有文件以进行更改。如果其中一个文件被更新,代码将被重新编译,所以你不必手动运行整个构建。

我们添加一个用于启动 webpack 的观察模式的 npm script 脚本:

{
  "name": "webpack-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack",
    "watch": "webpack --watch",
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "clean-webpack-plugin": "^0.1.17",
    "css-loader": "^0.28.7",
    "csv-loader": "^2.1.1",
    "file-loader": "^1.1.5",
    "html-webpack-plugin": "^2.30.1",
    "style-loader": "^0.19.0",
    "webpack": "^3.9.1",
    "xml-loader": "^1.2.1"
  },
  "dependencies": {
    "lodash": "^4.17.4"
  }
}

现在,你可以在命令行中运行 npm run watch,就会看到 webpack 编译代码,然而却不会退出命令行。这是因为 script 脚本还在观察文件。

唯一的缺点是,为了看到修改后的实际效果,你需要刷新浏览器。如果能够自动刷新浏览器就更好了,可以尝试使用 webpack-dev-server,恰好可以实现我们想要的功能。

使用webpack-dev-server

webpack-dev-server 为你提供了一个简单的 web 服务器,并且能够实时重新加载(live reloading)。

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

修改配置文件,告诉开发服务器(dev server),在哪里查找文件:
webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
    // entry: './src/index.js',
    entry:{
        app:'./src/index.js',
        print:'./src/print.js'
    },
    output: {
        // filename: 'bundle.js',
        filename:'[name].bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    module:{
        rules:[
            ...
        ]
    },
    plugins:[
        new CleanWebpackPlugin(['dist']),//清理的文件夹
        new HtmlWebpackPlugin({
            title:'Output Management'
        })
    ],
    devtool:'inline-source-map',
    devServer:{
        contentBase:'./dist'
    }
};

以上配置告知 webpack-dev-server,在 localhost:8080 下建立服务,将 dist 目录下的文件,作为可访问文件。

让我们添加一个 script 脚本,可以直接运行开发服务器(dev server):
package.json

{
  "name": "webpack-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack",
    "watch": "webpack --watch",
    "start": "webpack-dev-server --open"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "clean-webpack-plugin": "^0.1.17",
    "css-loader": "^0.28.7",
    "csv-loader": "^2.1.1",
    "file-loader": "^1.1.5",
    "html-webpack-plugin": "^2.30.1",
    "style-loader": "^0.19.0",
    "webpack": "^3.9.1",
    "webpack-dev-server": "^2.9.5",
    "xml-loader": "^1.2.1"
  },
  "dependencies": {
    "lodash": "^4.17.4"
  }
}

我这边试了一下后,发现如果webpack-dev-server启动起来的话,还需要安装下面的东西

cnpm install --save-dev parseurl
cnpm install --save-dev express 

然后才能启动起来。
就是执行npm start命令。

使用webpack-dev-middleware

webpack-dev-middleware 是一个中间件容器(wrapper),它将通过 webpack 处理后的文件发布到一个服务器(server)。在内部 webpack-dev-server 它使用,然而,它可以作为一个单独的包来提供,可以进行更多的自定义设置来实现更多需求。接下来是一个 webpack-dev-middleware 配合 express server 的示例。

首先,安装 express 和 webpack-dev-middleware:

npm install --save-dev express webpack-dev-middleware

接下来我们需要对 webpack 的配置文件做一些调整,以确保中间件(middleware)功能能够正确启用:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
    // entry: './src/index.js',
    entry:{
        app:'./src/index.js',
        print:'./src/print.js'
    },
    output: {
        // filename: 'bundle.js',
        filename:'[name].bundle.js',
        path: path.resolve(__dirname, 'dist'),
+        publicPath:'/'
    },
    module:{
        rules:[
           ...
        ]
    },
    plugins:[
        new CleanWebpackPlugin(['dist']),//清理的文件夹
        new HtmlWebpackPlugin({
            title:'Output Management'
        })
    ],
    devtool:'inline-source-map',
    devServer:{
        contentBase:'./dist'
    }
};
webpack-demo
  |- package.json
  |- webpack.config.js
+ |- server.js
  |- /dist
  |- /src
    |- index.js
    |- print.js
  |- /node_modules

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 compiler = webpack(config);

// Tell express to use the webpack-dev-middleware and use the webpack.config.js
// configuration file as a base.
app.use(webpackDevMiddleware(compiler,{
    publicPath:config.output.publicPath
}));

// Serve the files on port 3000.
app.listen(3000, function () {
    console.log('Example app listening on port 3000!\n');
});

然后,我们添加一个npm srcipt,以便我们更方便地运行服务:
package.json

{
  "name": "webpack-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack",
    "watch": "webpack --watch",
    "start": "webpack-dev-server --open",
    "server":"node server.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "clean-webpack-plugin": "^0.1.17",
    "css-loader": "^0.28.7",
    "csv-loader": "^2.1.1",
    "express": "^4.16.2",
    "file-loader": "^1.1.5",
    "html-webpack-plugin": "^2.30.1",
    "parseurl": "^1.3.2",
    "style-loader": "^0.19.0",
    "webpack": "^3.9.1",
    "webpack-dev-middleware": "^1.12.2",
    "webpack-dev-server": "^2.9.5",
    "xml-loader": "^1.2.1"
  },
  "dependencies": {
    "lodash": "^4.17.4"
  }
}

现在,我们运行npm run server,结果如下:

Hash: ad60018b6b26603b9a3a
Version: webpack 3.9.1
Time: 1472ms
          Asset       Size  Chunks                    Chunk Names
  app.bundle.js    1.48 MB    0, 1  [emitted]  [big]  app
print.bundle.js    6.42 kB       1  [emitted]         print
     index.html  256 bytes          [emitted]         
   [0] ./src/print.js 85 bytes {0} {1} [built]
   [1] ./src/index.js 430 bytes {0} [built]
   [2] ./node_modules/.4.17.4@lodash/lodash.js 540 kB {0} [built]
   [3] (webpack)/buildin/global.js 509 bytes {0} [built]
   [4] (webpack)/buildin/module.js 517 bytes {0} [built]
   [5] ./src/style.css 1.04 kB {0} [built]
   [6] ./node_modules/.0.28.7@css-loader!./src/style.css 198 bytes {0} [built]
   [7] ./node_modules/.0.28.7@css-loader/lib/css-base.js 2.26 kB {0} [built]
   [8] ./node_modules/.0.19.0@style-loader/lib/addStyles.js 9.41 kB {0} [built]
   [9] ./node_modules/.0.19.0@style-loader/lib/urls.js 3.01 kB {0} [built]
Child html-webpack-plugin for "index.html":
         Asset    Size  Chunks  Chunk Names
    index.html  544 kB       0  
       [0] ./node_modules/.2.30.1@html-webpack-plugin/lib/loader.js!./node_modules/.2.30.1@html-webpack-plugin/default_index.ejs 546 bytes {0} [built]
       [1] ./node_modules/.4.17.4@lodash/lodash.js 540 kB {0} [built]
       [2] (webpack)/buildin/global.js 509 bytes {0} [built]
       [3] (webpack)/buildin/module.js 517 bytes {0} [built]
webpack: Compiled successfully.

调整文本编辑器

使用自动编译代码时,可能会在保存文件时遇到一些问题。某些编辑器具有“安全写入”功能,可能会影响重新编译。

要在一些常见的编辑器中禁用此功能,请查看以下列表:

Sublime Text 3 - 在用户首选项(user preferences)中添加 atomic_save: "false"。
IntelliJ - 在首选项(preferences)中使用搜索,查找到 "safe write" 并且禁用它。
Vim - 在设置(settings)中增加 :set backupcopy=yes。
WebStorm - 在 Preferences > Appearance & Behavior > System Settings 中取消选中 Use "safe write"。