Webpack学习笔记(官网教程)

参考资料:webpack官方指南
GitHub源码:https://github.com/GYQ-LQ/quinn-webpack-demo

demo01 安装&起步 (GitHub)

安装

全局安装
npm install webpack
项目本地安装
mkdir demo01 && cd demo01
npm init -y
npm install webpack webpack-cli --save-dev

起步

创建一个 bundle 文件

首先,我们稍微调整下目录结构,将“源”代码(/src)从我们的“分发”代码(/dist)中分离出来。“源”代码是用于书写和编辑的代码。“分发”代码是构建过程产生的代码最小化和优化后的“输出”目录,最终将在浏览器中加载.

构建命令:npx webpack
使用一个配置文件 webpack.config.js
const path = require('path');
module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
};

npx webpack --config webpack.config.js

  • 如果 webpack.config.js 存在,则 webpack 命令将默认选择使用它。我们在这里使用 --config 选项只是向你表明,可以传递任何名称的配置文件。这对于需要拆分成多个文件的复杂配置是非常有用。
NPM 脚本(NPM Scripts)
// 现在,可以使用 npm run build 命令,来替代我们之前使用的 npx 命令。
{
    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "build": "webpack"
    }
}

demo02 管理资源 (GitHub)

加载 CSS

npm install --save-dev style-loader css-loader

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'
+         ]
+       }
+     ]
+   }
  };

加载图片

npm install --save-dev file-loader

rules: [{
    test: /\.(png|svg|jpg|gif)$/,
    use: [
        'file-loader'
    ]
}, ];

file-loader 和 url-loader 可以接收并加载任何文件,可以将它们用于任何类型的文件,包括字体

加载字体

rules: [{
    test: /\.(woff|woff2|eot|ttf|otf)$/,
    use: [
        'file-loader'
    ]
}, ];

加载数据

如 JSON、CSV、TSV 和 XML

npm install --save-dev csv-loader xml-loader
rules: [{
    test: /\.(csv|tsv)$/,
    use: [
        'csv-loader'
    ]
}, {
    test: /\.xml$/,
    use: [
        'xml-loader'
    ]
}, ];

data.xml

<?xml version="1.0" encoding="UTF-8"?>
<note>
  <to>Mary</to>
  <from>John</from>
  <heading>Reminder</heading>
  <body>Call Cindy on Tuesday</body>
</note>

demo03 管理输出 (GitHub)

多入口文件

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

设定 HtmlWebpackPlugin

npm run build 自动构建生成 /dist/index.html

npm install --save-dev html-webpack-plugin

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

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

清理 /dist 文件夹

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

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

npm install clean-webpack-plugin --save-dev
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
plugins: [
	new CleanWebpackPlugin()
],

Manifest

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

npm install --save-dev webpack-manifest-plugin
const ManifestPlugin = require('webpack-manifest-plugin');
module.exports = {
    // ...
    plugins: [
      new ManifestPlugin()
    ]
};

生成文件 manifest.json

{
  "app.js": "app.bundle.js",
  "print.js": "print.bundle.js",
  "index.html": "index.html"
}

demo04 自动编译代码的简单开发服务器(开发) (GitHub)

使用 source map

当 webpack 打包源代码时,可能会很难追踪到错误和警告在源代码中的原始位置。

module.exports = {
    entry: {
      app: './src/index.js',
      print: './src/print.js'
    },
   devtool: 'inline-source-map',
};

devtool 此选项控制是否生成,以及如何生成 source map。
使用  SourceMapDevToolPlugin  进行更细粒度的配置。查看  source-map-loader  来处理已有的 source map。
你可以直接使用  SourceMapDevToolPlugin/EvalSourceMapDevToolPlugin  来替代使用  devtool  选项,因为它有更多的选项。
切勿同时使用  devtool  选项和  SourceMapDevToolPlugin/EvalSourceMapDevToolPlugin  插件。devtool  选项在内部添加过这些插件,所以你最终将应用两次插件。

选择一个开发工具

每次要编译代码时,手动运行  npm run build  就会变得很麻烦。
webpack 中有几个不同的选项,可以帮助你在代码发生变化后自动编译代码:

1. webpack’s Watch Mode

使用观察模式 webpack --watch

"scripts": {
      "test": "echo \"Error: no test specified\" && exit 1",
      "watch": "webpack --watch",
      "build": "webpack"
},

2. webpack-dev-server

使用 webpack-dev-server

  • webpack.config.js:
npm install --save-dev webpack-dev-server

module.exports = {
    entry: {
      app: './src/index.js',
      print: './src/print.js'
    },
   devtool: 'inline-source-map',
   devServer: {
     contentBase: './dist'
   }
};
  • package.json
"scripts": {
      "test": "echo \"Error: no test specified\" && exit 1",
      "watch": "webpack --watch",
      "start": "webpack-dev-server --open",
      "build": "webpack"
},

3. webpack-dev-middleware

webpack-dev-middleware 是一个容器(wrapper),它可以把 webpack 处理后的文件传递给一个服务器(server)。 webpack-dev-server 在内部使用了它,同时,它也可以作为一个单独的包来使用,以便进行更多自定义设置来实现更多的需求。接下来是一个 webpack-dev-middleware 配合 express server 的示例

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

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

  • webpack.config.js
  module.exports = {
    entry: {
      app: './src/index.js',
      print: './src/print.js'
    },
    output: {
      filename: '[name].bundle.js',
      path: path.resolve(__dirname, 'dist'),
+     publicPath: '/'
    }
  };
  • 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 script,以使我们更方便地运行

  • package.json
 {
    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1",
      "watch": "webpack --watch",
      "start": "webpack-dev-server --open",
+     "server": "node server.js",
      "build": "webpack"
    },
  }

npm run server 访问: http://localhost:3000

结论:学会了如何自动编译代码,并运行一个简单的开发服务器(development server)!!!


demo05 模块热替换 (GitHub)

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

更改 print.js 中 console.log 的输出内容,你将会在浏览器中即可以看到更新。

  • print.js
 export default function printMe() {
-   console.log('I get called from print.js!');
+   console.log('Updating print.js...')
  }

启用 HMR

方式一:配置 webpack.config.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 = {
    entry: {
-      app: './src/index.js',
-      print: './src/print.js'
+      app: './src/index.js'
    },
    devtool: 'inline-source-map',
    devServer: {
      contentBase: './dist',
+     hot: true
    },
    plugins: [
      new CleanWebpackPlugin(['dist']),
      new HtmlWebpackPlugin({
        title: 'Hot Module Replacement'
      }),
+     new webpack.NamedModulesPlugin(),
+     new webpack.HotModuleReplacementPlugin()
    ],
    output: {
      filename: '[name].bundle.js',
      path: path.resolve(__dirname, 'dist')
    }
  };

方式二:你可以通过命令来修改 webpack-dev-server 的配置:webpack-dev-server --hotOnly。

{
-  "start": "webpack-dev-server --open",
+  "start": "webpack-dev-server --hotOnly",
}

通过 Node.js API

方式三: webpack dev server 和 Node.js API

当使用 webpack dev server 和 Node.js API 时,不要将 dev server 选项放在 webpack 配置对象(webpack config object)中。而是,在创建选项时,将其作为第二个参数传递。例如:

new WebpackDevServer(compiler, options)

想要启用 HMR,还需要修改 webpack 配置对象,使其包含 HMR 入口起点。webpack-dev-server package 中具有一个叫做 addDevServerEntrypoints 的方法,你可以通过使用这个方法来实现。这是关于如何使用的一个小例子:

  • dev-server.js
const webpackDevServer = require('webpack-dev-server');
const webpack = require('webpack');

const config = require('./webpack.config.js');
const options = {
  contentBase: './dist',
  hot: true,
  host: 'localhost'
};

webpackDevServer.addDevServerEntrypoints(config, options);
const compiler = webpack(config);
const server = new webpackDevServer(compiler, options);

server.listen(5000, 'localhost', () => {
  console.log('dev server listening on port 5000');
});

运行 node dev-server.js

方式四:如果你使用了 webpack-dev-middleware 而没有使用 webpack-dev-server,请使用 webpack-hot-middleware package 包,以在你的自定义服务或应用程序上启用 HMR。

问题

模块热替换可能比较难掌握。为了说明这一点,我们回到刚才的示例中。如果你继续点击示例页面上的按钮,你会发现控制台仍在打印这旧的 printMe 功能。

这是因为按钮的 onclick 事件仍然绑定在旧的 printMe 函数上

为了让它与 HMR 正常工作,我们需要使用 module.hot.accept 更新绑定到新的 printMe 函数上:

  • index.js
import _ from 'lodash';
  import printMe from './print.js';

  function component() {
    var element = document.createElement('div');
    var btn = document.createElement('button');

    element.innerHTML = _.join(['Hello', 'webpack'], ' ');

    btn.innerHTML = 'Click me and check the console!';
    btn.onclick = printMe;  // onclick 事件绑定原始的 printMe 函数上

    element.appendChild(btn);

    return element;
  }

- document.body.appendChild(component());
+ let element = component(); // 当 print.js 改变导致页面重新渲染时,重新获取渲染的元素
+ document.body.appendChild(element);

  if (module.hot) {
    module.hot.accept('./print.js', function() {
      console.log('Accepting the updated printMe module!');
-     printMe();
+     document.body.removeChild(element);
+     element = component(); // 重新渲染页面后,component 更新 click 事件处理
+     document.body.appendChild(element);
    })
  }

HMR 修改样式表

借助于 style-loader 的帮助,CSS 的模块热替换实际上是相当简单的。当更新 CSS 依赖模块时,此 loader 在后台使用 module.hot.accept 来修补(patch) <style> 标签。

npm install --save-dev style-loader css-loader
  • webpack.config.js

  module.exports = {
+   module: {
+     rules: [
+       {
+         test: /\.css$/,
+         use: ['style-loader', 'css-loader']
+       }
+     ]
+   },
  };

其他代码和框架

社区还有许多其他 loader 和示例,可以使 HMR 与各种框架和库(library)平滑地进行交互

  • React Hot Loader:实时调整 react 组件。
  • Vue Loader:此 loader 支持用于 vue 组件的 HMR,提供开箱即用体验。
  • Elm Hot Loader:支持用于 Elm 程序语言的 HMR。
  • Redux HMR:无需 loader 或插件!只需对 main store 文件进行简单的修改。
  • Angular HMR:No loader necessary! A simple change to your main NgModule file is all that’s required to have full control over the HMR APIs.没有必要使用 loader!只需对主要的 NgModule 文件进行简单的修改,由 HMR API 完全控制。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值