webpack
一句话总结,webpack是用来编译打包代码的.
在当下ES6语法在项目中屡见不鲜的情况下,一些浏览器其实对ES6还不是很友好,这时候就需要有个中间介质来做翻译.那webpack就是市面上众多'翻译'中的一员.
在日常开发中,我们除了一些样式/图片元素还会使用很多框架,类库...来提升我们的输出效率.让我们可以更有效率的完成开发工作.比如: vue.js、Eslint、Less/Sass、Es6、image...但是就会出现一个问题,这些东西,或者说模块浏览器不认识,这就需要使用webpack
来让浏览器认识这些代码.
loader
loader用于对模块源代码进行转换.loader可以将不同语言转换为JavaScript,可以将内联图像转换为data URL,他可以让开发者直接在JavaScript模块中使用import();
loader就是一个导出的function.当要对资源进行转换时,会调用这个函数.
loader是怎么在项目中使用的
可以直接使用path
到一个loader.js
const path = require('path');
module.exports = {
//...
module: {
rules: [
{
test: /\.js$/,
use: [
{
loader: path.resolve('path/to/loader.js'),
options: {
/* ... */
},
},
],
},
],
},
};
要测试多个loader,使用resolveLoader.modules
来配置webpack在什么地方去查找:
const path = require('path');
module.exports = {
//...
resolveLoader: {
modules: ['node_modules', path.resolve(__dirname, 'loaders')],
},
};
如果是通过npm之类的包管理工具安装的loader:
module.exports = {
//...
module: {
rules: [
{
test: /\.js/,
use: ['bar-loader', 'foo-loader'],
},
],
},
};
如何编写一个loader
一个loader首先需要导出一个函数, 这个函数会拿到需要编译处理的内容,然后对这个内容进行一些列的处理,最后返回处理后的内容.
module.exports = function(source) {
// ...
return source;
}
下面我们来实现一个简单的编译markdown的loader来落地上面的想法:
- 新建文件夹loader,npm init 初始化package.json然后安装webpack-cli webpack-dev-server webpack
npm init
npm i -D webpack webpack-cli webpack-dev-server
- 创建webpack.config.js
var path = require('path')
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.md$/,
// html是用来处理md转换之后生成的html的
use: ['html-loader', './src/loader/md-loader'],
},
],
},
devServer: {
contentBase: './dist',
overlay: {
warnings: true,
errors: true,
},
open: true,
},
}
- 创建index.js 使用 index.md模块
import md from './index.md'
var content = document.createElement('div')
content.innerHTML = md
document.body.appendChild(content)
- 新建loader文件 添加md-loader.js
var marked = require('marked')
module.exports = function (source) {
var html = marked(source)
return html
}
然后run 就可以看到页面上展示出我们markdown中的内容了. 源码入口
上面我们实现的是一个简单的loader,实质上loader有很多options可供配置选择.loader-utils
提供了很多有用的工具.更多loader配置可以移步.
常用loader示例
- babel-loader
- vue-loader
- html-loader
- style-loader
- css-loader
- sass-loader
- file-loader
- url-loader ...
plugin
plugin比loader更强大,当loader满足不了你的需求时就需要plugin了.plugin向开发者提供了webpack引擎中完整能力.用官方的话说就是创建plugin比创建loader更高级!
plugin是怎么在项目中使用的
webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
const webpack = require('webpack'); // 访问内置的插件
const path = require('path');
module.exports = {
entry: './path/to/my/entry/file.js',
output: {
filename: 'my-first-webpack.bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: 'babel-loader',
},
],
},
plugins: [
new webpack.ProgressPlugin(), // 用于自定义编译过程中的进度报告
// 将生成一个 HTML 文件,并在其中使用 script 引入一个名为 my-first-webpack.bundle.js 的 JS 文件, 这样我们就不用像上文那样在index.html中引入打包之后的bundle.js文件了.
new HtmlWebpackPlugin({ template: './src/index.html' }),
],
};
如何编写一个plugin
一个plugin的构成部分分为以下几点:
- 一个具名的
JavaScript函数
- 函数的prototype上要有一个
apply
方法 - 指定一个触及到webpack本身的
钩子(hooks)
complier hookscomplier
代表了整个webpack从启动到关闭的生命周期
- 操作webpack内部的
实例特定数据
compilation hookscompilation
只代表一次单独的编译
- 实现功能后调用
callback
// 一个 JavaScript class
class MyExampleWebpackPlugin {
// 将 `apply` 定义为其原型方法,此方法以 compiler 作为参数
apply(compiler) {
// 指定要附加到的事件钩子函数
compiler.hooks.emit.tapAsync(
'MyExampleWebpackPlugin',
(compilation, callback) => {
// 钩子第二个参数以compilation 为参数
// 使用 webpack 提供的 plugin API 操作构建结果
compilation.addModule(/* ... */)
callback()
}
)
}
}
module.exports = MyExampleWebpackPlugin
下面我们实现一个简单的代码来实现html-webpack-plugin(它的源码还是比较复杂的,这边只是实现简单功能,不做过多参数配置).
- 首先,npm init -y 并安装webpack以及 webpack-cli.我这边使用了webpack-dev-server(手动执行webpack太麻烦,起服务方便)
{
...
"dependencies": {
"webpack": "^4.46.0",
"webpack-dev-server": "^3.11.2"
},
"devDependencies": {
"webpack-cli": "^3.3.12"
}
}
- 创建webpack.config.js
var path = require('path')
var MyExampleWebpackPlugin = require('./src/plugins/index')
module.exports = {
mode: 'development',
devServer: {
contentBase: './dist',
overlay: {
warnings: true,
errors: true,
},
open: true,
},
entry: '/src/app.js',
output: {
path: path.resolve(__dirname, './dist'),
filename: 'bundle.js',
},
plugins: [new MyExampleWebpackPlugin()],
}
- 编写plugin
class MyExampleWebpackPlugin {
apply(compiler) {
compiler.hooks.emit.tapAsync(
'MyExampleWebpackPlugin',
(compilation, callback) => {
let html = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>
</body>
<script src="./bundle.js"></script>
</html>
`
compilation.assets['index.html'] = {
source() {
return html
},
size() {
return html.length
},
}
callback()
}
)
}
}
- 执行npm run dev就ok了
对了,这里可能会碰到一个问题就是执行webpack-dev-server会起一个服务,然后执行配置中的内容, 但是它不会生成打包后的文件.根本原因是webpack与webpack-dev-server是两个工具,后者不做打包的事情,就是起个服务.
打包的话执行./node_modules/.bin/webpack
源码入口.
常用的plugin示例
- HtmlWebpackPlugin
- CleanWebpackPlugin
- CopyWebpackPlugin
- BannerPlugin
- TerserWebpackPlugin
- UglifyjsWebpackPlugin
- DLLPlugin与DllReferencePlugin
- HotModuleReplacementPlugin
总结
webpack
与tapable
有这密不可分的关系,上文中的compiler
与compilation
都是tapable实例化出来的.上文中也提到了它们各自有很多hooks
,可以分别用在编译或者打包不同进行时间做处理.
在现在的开发工作中, webpack与我们息息相关.对于它海量的文档API,其实不用望而却步,我们需要理解它的目的,以及它做的事情,这样用起来肯定游刃有余.至于API,我认为常用的比如loader/plugin稍加了解即可,在实际业务场景中使用到的话,去做深入学习即可.
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!