本文也是多次学习webpack积累下来的知识点,一直在云笔记里。

webpack的原理

webpack构建流程

从启动webpack构建到输出结果经历了一系列过程,它们是:

  • 解析webpack配置参数,合并从shell传入和webpack.config.js文件里配置的参数,生产最后的配置结果。
  • 注册所有配置的插件,好让插件监听webpack构建生命周期的事件节点,以做出对应的反应。
  • 从配置的entry入口文件开始解析文件构建AST语法树,找出每个文件所依赖的文件,递归下去。
  • 在解析文件递归的过程中根据文件类型和loader配置找出合适的loader用来对文件进行转换。
  • 递归完后得到每个文件的最终结果,根据entry配置生成代码块chunk。
  • 输出所有chunk到文件系统。

需要注意的是,在构建生命周期中有一系列插件在合适的时机做了合适的事情,比如UglifyJsPlugin会在loader转换递归完后对结果再使用UglifyJs压缩覆盖之前的结果

配置webpack就是在配置一个node的模块module.exports用于webpack来读取

1、webpack与Rollup的优缺点和区别?

webpack的优点:

  • 专注于处理模块化的项目,能做到开箱及用、一步到位
  • 可用plugin扩展,完整好用又不失灵活
  • 使用场景不限于web开发
  • 社区庞大

webapck的缺点:

  • 只能用于采用模块化开发的项目

Rollup

  • 可以对es6进行 Tree Shaking
  • 它支持导出ES模块的包
  • 它支持程序流分析,能更加正确的判断项目本身的代码是否有副作用

2、devserver的使用

webpack-dev-server是一个启动服务的程序,可以自动去,读取webpack.config.js 的文件。执行webpack-dev-server来启动,就可以来自动刷新页面,内部的原理是express的启服务,用webSocket来通知浏览器。

3、webapck配置选项

  • Entry:入口,webpack执行构建的第一步从entry开始
  • Module:模块,一切都是模块,一个模块对应一个文件。webapck从entry开始递归找出依赖的模块。
  • Chunk:代码块,一个chunk由多个模块组合而成,用于代码合并与分割。
  • Loader:模块转换器,将模块的原内容按照要求转换成新的内容。
  • Plugin: 扩展插件,在特定时机执行
  • Output:输出结果,把处理的最终想要的代码输出结果

4、Entry的配置

1、context是webpack寻找相对路径文件会以context为根目录
module.exports = {
context: path.resolve(__dirname, './app'),
entry:'./main.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, './dist')
}
}
2、Entry
  • string 'app/'
  • array ['app/a.js', 'app/b.js'] 多入口,单Chunk
  • object [a:'a.js', b:'b.js'] 配置多个入口,每个入口生成一个Chunk

也可以动态的配置,就是返回函数,可以同步也可以异步

同步
entry:()=>{
return {
a: './pages/a',
b:'./pages/a'
}
},
异步
entry:new Promise((resolve)=>{
resolve({
a: '/a.js',
b:'/b.js'
})
}),

5、Output配置

output是一个对象,里面有配置项

  1. filename 输出文件的名称,是string
  • [id Chunk的唯一标识,从0开始]
  • [name Chunk的名称]
  • [hash] Chunk的唯一标识Hash[hash:8]可以指定长度
  • [chunkhash] Chunk内容的Hash值,比如 ExtractTextWebapckPlugin就是用的那个
  1. chunkFilename 配置无入口的Chunk的输出名字,比如CommonChunkPlugin import('path/')动态加载
  2. path输出文件存在的本地目录:path: path.resolve(__dirname, './dist')
  3. publicPath 配置上传cnd的路径
  4. corssOriginLoading 在异步加载是,利用JONSP的原理动态插入script,用来控制crossorigin的值

    当本地尝试使用 window.onerror 去记录脚本的错误时,跨域脚本的错误只会返回 Script error。

    HTML5 新的规定,是可以允许本地获取到跨域脚本的错误信息,但有两个条件:
  • 一是跨域脚本的服务器必须通过 Access-Controll-Allow-Origin 头信息允许当前域名可以获取错误信息
  • 二是当前域名的 script 标签也必须指明 src 属性指定的地址是支持跨域的地址,也就是 crossorigin 属性

可以取一下值:

  • anonymous(默认) 匿名的,加载不会带上用户的cookies
  • use-credentials,在加载脚本是会带上用户的cokires
  1. libraryTarget 和 library
  2. 构建一个可以被导入使用的库
  • libraryTarget 何种方式,var(默认)comomjs/commonjs2/this/window/global
  • library 导出的名字

6、module

  • rules来配置Loader
rules: [{
test: '/\.js$/',//命中文件
use: ['babel-loader?cacheDirectory'],//指定loader 解析是从后向前
include: path.resolve(__dirname, 'src'),//包括
exclude: path.resolve(__dirname, 'node_modules')//排除
},{
test: /.vue$/,
use: ['vue-loader']
}] vue需要使用vue-loader
  • noParse 来忽略没有采用模块化的文件的递归

noParse: /jquery|chartjs/ //一般是正则 被忽略的文件不应该有import/requie/define等
  • parse可以细颗粒度配置解析比如AMD,commonJS等

7、resolve 配置webpack如何寻找模块

resolve: {
alias: {
components : './src/components'
},
mainFields: ['jsnext:main', 'browser', 'main'],//jsnext 是支持ES6的模式进入
extension: ['.ts','.js','.json'],//后缀列表 //延长;延期
modules: ['./src/components', 'node_modules'],//指定本地解析 import 'button'
enforceExtension: true,//开启必须带后缀
},

8、plugin 接受数组,plugin的实例

9、devServer 使用devserver启动还生效

devServer:{
hot: true,//启用 webpack 的模块热替换特性
inline: true,//fasle是 iframe 模式
historyApiFallback: true,//spa history的模式,
任何请求都会返回index.html 也可以使用重写rewrites来详细配置
contentBase:[path.join(__dirname, "public"),
path.join(__dirname, "assets")],//提供静态文件 string fales关闭 array
host:'0.0.0.0',//服务器外部可访问
port: '9090',//端口
disableHostCheck: true,//关闭host,devServer默认是接受本地请求配合host使用
https:true,//开启https或者自己导入证书
compress: true,//默认false开启gzip压缩 压缩
open: true,//打开浏览器
proxy:{ // credentials 证书 设置成include,表示允许跨越传递cookie
"/api": "http://localhost:3000"
}
},

10、其他配置项

target:'web',//构建到的环境比如node web webworker等
devtool:'source-map',// 可以设置为false
watch:true,//监听文件,默认是关闭的devserer默认打开
externals:{
jquery: 'jQuery'
},
resolveLoader:{ //加载本地loader
},

11、为单页应用生成html

使用 html-webpack-plugin

12、其他常用Loader

file-loader 将js和css中的图片等替换成正确的地址,输出在文件中

url-loader 可以将文件的内容经过base64编码后注入js或者css中,但是要限制大小

{
exclude: [
/\.(js|jsx)(\?.*)?$/,
/\.(css|scss)$/,
/\.json$/,
/\.bmp$/,
/\.jpe?g$/,
/\.png$/,
],
loader: require.resolve('file-loader'),
options: {
name: 'static/media/[name].[hash:8].[ext]',
},
},
{
test: [/\.bmp$/, /\.jpe?g$/, /\.png$/],
loader: require.resolve('url-loader'),
options: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]',
},
},

raw-loader 和 svg-inline-loader 可以把svg内嵌到网页,把svg当图片用,可以用上面的。

13、Source Map

以方便在浏览器通过代码调试

devtool有很多的取值,由一下6个关键字随意组合而成

  • eval: 用eval语句包裹需要安装的模块

  • source-map:生成独立的Source Map 文件

  • hidden:不在javascript文件中支出source map 文件的所在,这样浏览器就不会自动加载source map

  • inline:将生成的source map转成base64格式内嵌在javascript文件中

  • cheap:在生成的source map中不会包含列信息,那样计算量更小,输出文件更小,同时loader输出的source map不会被采用

  • module:来时loader的source map 被简单处理成每行一个模块

  • eval: 生成代码 每个模块都被eval执行,并且存在@sourceURL

  • cheap-eval-source-map: 转换代码(行内) 每个模块被eval执行,并且sourcemap作为eval的一个dataurl

  • cheap-module-eval-source-map: 原始代码(只有行内) 同样道理,但是更高的质量和更低的性能

  • eval-source-map: 原始代码 同样道理,但是最高的质量和最低的性能

  • cheap-source-map: 转换代码(行内) 生成的sourcemap没有列映射,从loaders生成的sourcemap没有被使用

  • cheap-module-source-map: 原始代码(只有行内) 与上面一样除了每行特点的从loader中进行映射

  • source-map: 原始代码 最好的sourcemap质量有完整的结果,但是会很慢

eval和.map文件都是sourcemap实现的不同方式,虽然大部分sourcemap的实现是通过产生.map文件, 但并不表示只能通过.map文件实现。下面是eval模式后产生的模块代码

cheap关键字的配置中只有行内,列信息指的是代码的不包含原始代码的列信息

  • 在开发环境 用source-map 那个最完整 或者cheap-module-eval-source-map 那个最快
  • 在生产环境就flase 或者 hidden-source-map 为错误搜集用
  • 如果需要加载模块的source-map 需要使用source-map-loader
  • vue-cli 用的devtool: '#eval-source-map',

14、代码检测和npm配合

与npm 配着
npm 可以运行node__modules里安装的程序
可以缩短命令
代码检测

javascript 用eslint 用.eslintrc json 文件配置 eslint-loader enforce: 'pre'

ts 用TSlint tslint.json 配置 tslint-loader

css stylelint 用.stylelintrc 配置 StyleLintPlugin 插件来处理

代码检测会变慢构建速度,可以配置IDE来检测,同时配置git Hook在代码提交时检测

15、node运行webapck和中间件

var config = require('../config')
var compiler = webpack(webpackConfig)

调用compiler的watch可以监听文件变化

require('webpack-dev-middleware')是express的一个插件

var app = express()
var compiler = webpack(webpackConfig) var devMiddleware = require('webpack-dev-middleware')(compiler, {
publicPath: webpackConfig.output.publicPath,
stats: {
colors: true,
chunks: false
}
})

但是不支持hot模式需要require('webpack-hot-middleware')

app.use(hotMiddleware)

代理使用

var proxyMiddleware = require('http-proxy-middleware')

16、webapck构建优化

1、减小文件的搜索范围
  1. 优化loader配置,利用好include和exclude
  2. 优化resolve.modules 使用绝对路径
modules: [path.resolve(__dirname, 'node_modules')]
  1. alias 指向 x.min.js 文件,但是lodash不适合
alias: {
react: path.resolve(__dirname, './node_modules/react/dist/react.min.js')
},
  1. noParse 配置不解析
noParse: /jquery|chartjs/ //一般是正则 被忽略的文件不应该有import/require/define等
2、优化构建过程
  1. babel-loader 加 cacheDirectory
  2. DllPlugin 官方推荐做法是把不常变动的文件打DLL

工程就把 react react-dom prop-types classnames mobx mobx-react lodash moment polyfill 等打进来 可以使用 [npm version]_dll.js 用 npm version 的话只要 version 一改变我们会重新打包,比如升级了 react ,我们就会 version +,就会重新打包。

先创建一个webpack.config.dll.js

执行webpack --config ./webpack.config.dll.js把需要dll的文件输出到dist/dll

const webpack = require('webpack');
const path = require('path'); const {version} = require('./package.json'); module.exports = {
entry: {
'react': [
'react', 'react-dom',
'prop-types',
'classnames',
'lodash', 'moment'
]
},
output: {
path: path.join(__dirname, 'dist/dll'),
filename: `[name].${version}.js`,
library: 'dll_[name]',
publicPath: '/dist/dll/'
},
plugins: [
new webpack.DllPlugin({
path: path.join(__dirname, 'dist/dll/', '[name].manifest.json'),
name: 'dll_[name]'
})
]
};

在webapck配置文件中使用

new webpack.DllReferencePlugin({
context: __dirname,
// 在这里引入 manifest 文件
manifest: require('./dist/dll/react.manifest.json')
}),
//把js插入到html文件中
new AddAssetHtmlPlugin({
filepath: require.resolve(`./dist/dll/${getDLLFileName()}`),
outputPath: 'dll',
includeSourcemap: false,
hash: true,
publicPath: '/dist/dll/'
})

原理就是提前构建,缓存起来,用window的全局变量来取。

  1. happypack 对 build 的速度大大大提示,可以多线程打包,cache 也让 rebuild 加快
{
test: /\.(js|jsx)$/,//命中文件
use: 'happypack/loader?id=js',//指定loader
include: path.resolve(__dirname, 'src'),//包括
exclude: path.resolve(__dirname, 'node_modules')//排除
}, {
test: /\.(css|scss)$/,
loader: 'happypack/loader?id=css'
}
new HappyPack({
id: 'js',
threadPool: happyThreadPool,
loaders: [{
path: 'babel-loader',
query: {
cacheDirectory: true
}
}]
}),
new HappyPack({
id: 'css',
threadPool: happyThreadPool,
loaders: ['style-loader','css-loader', 'sass-loader']
}),

原理:happypack 的原理是让loader可以多进程去处理文件,css和js,图片和文件支持不好

  1. Devtool 使用 开发用cheap-module-eval-source-map 那个最快

  2. 压缩 UglifyJsParallelPlugin在webpack2.0以后支持并行,就可以弃用

  3. 开启自动刷新(iframe会比inline快一点)和热更新热替换(hot 开启) 优化就是把node_modules 排除

  4. 区分环境

if (isDev) {
config.plugins.push(new webpack.NamedModulesPlugin()); //显示模块更新名字
config.plugins.push(new webpack.HotModuleReplacementPlugin()); //hot更新插件 config.devServer = {
hot: true,
contentBase: './',
historyApiFallback: {
index: "/build/index.html"
},
publicPath: '/build/',
host: '0.0.0.0'
};
config.devtool = 'eval';
} else {
config.plugins.push(new webpack.optimize.UglifyJsPlugin({ // 开启压缩
cache: true,
parallel: true,
compress: {
warning: fasle,// 是否删除一个警告信息fasle删除
drop_console: true,//删除console
collapse_vars: true,是否内嵌虽然已定义但是只用到一次的变量。
reduce_vars: true ,提取多次的变量
},
output: {
comments: false,//是否删除注释,默认是不删除,设置为false,删除所有的注释
beautify: fasle, //保留空格和制表符 建议false关闭,最紧凑的输出
} })); config.devtool = '#source-map';
}

8、压缩css 在css-loader开启minimize选项 和 提取css到单独的文件

{
test: /\.(css|less)$/,
loader: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: 'happypack/loader?id=css'
})
},
new ExtractTextPlugin('css/[name].[contenthash:8].css')

9、在webapck中接入cdn

  • 在output.publicPath 中设置javascript的地址
  • 在css-loader.publicPath 中设置css文件中导入的资源的地址
  • 在HtmlWebpackPlugin或者WebPlugin.stylePublicPath 设置css单独是文件的资源

10、Tree Shaking 去除重复代码 ,webapck没有程序流分析,避免不了babel产生的副作用

11、以模块化来引入

// 原来的引入方式
import {debounce} from 'lodash'; //按模块化的引入方式
import debounce from 'lodash/debounce';

12、使用异步的模块加载

require.ensure来设置哪些模块需要异步加载,webpack会将它打包到一个独立的chunk中

$('.bg-input').click(() => {
console.log('clicked, loading async.js') require.ensure([], require => { require('./components/async2').log();
require('./components/async1').log();
console.log('loading async.js done');
});
});

import(*) 是新的按需加载,在react-router4中不能使用require.ensure要使用getAsyncComponent函数

component = {
getAsyncComponent(() => {
import('./pages/login')
})
}

13、Scope Hoisting 作用域提升 webpack3的新功能

使用ModuleConcatenationPlugin插件来加快JS执行速度

这是webpack3的新特性(Scope Hoisting),其实是借鉴了Rollup打包工具来的,它将一些有联系的模块,放到一个闭包函数里面去,通过减少闭包函数数量从而加快JS的执行速度

new webpack.optimize.ModuleConcatenationPlugin({

        })

原理:原理其实很简单,分析模块之间的依赖关系,尽可能将被打散的模块合并到一个函数中,前提是不能造成代码冗余,源码必须采用es6语句。

14、提取公共代码

使用CommonsChunkPlugin提取公共的模块,可以减少文件体积,也有助于浏览器层的文件缓存,还是比较推荐的,那个是在最后打包的时候用的。

// 提取公共模块文件
new webpack.optimize.CommonsChunkPlugin({
chunks: ['home', 'detail'],
// 开发环境下需要使用热更新替换,而此时common用chunkhash会出错,可以直接不用hash
filename: '[name].js' + (isProduction ? '?[chunkhash:8]' : ''),
name: 'common'
}), // 切合公共模块的提取规则,有时后你需要明确指定默认放到公共文件的模块
// 文件入口配置
entry: {
home: './src/js/home',
detail: './src/js/detail',
// 提取jquery入公共文件
common: ['jquery', 'react', 'react-dom']
}, entry: {index:'./src/index.js',vendor: ['react','react-dom','react-router']}, new webpack.optimize.CommonsChunkPlugin({
name: "vendor",
filename: "vendor.js",
}),

15、prepack

利用抽象语法树(AST)来分析源码,过来问题大大,不建议使用

const PrepackWebpackPlugin = require('prepack-webapck-plugin').default;

module.exports = {
plugins: [
new PrepackWebpackPlugin()
] }

16、可视化的输出分析 Analyse webpack-bundle-analyzer

17、pwa构建

用 Webpack 构建接入 Service Workers 的离线应用要解决的关键问题在于如何生成上面提到的 sw.js 文件, 并且sw.js文件中的 cacheFileList 变量,代表需要被缓存文件的 URL 列表,需要根据输出文件列表所对应的 URL 来决定,而不是像上面那样写成静态值。

假如构建输出的文件目录结构为:

├── app_4c3e186f.js
├── app_7cc98ad0.css
└── index.html

那么 sw.js 文件中 cacheFileList 的值应该是:

var cacheFileList = [
'/index.html',
'app_4c3e186f.js',
'app_7cc98ad0.css'
];

Webpack 没有原生功能能完成以上要求,幸好庞大的社区中已经有人为我们做好了一个插件 serviceworker-webpack-plugin 可以方便的解决以上问题。 使用该插件后的 Webpack 配置如下:

const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const { WebPlugin } = require('web-webpack-plugin');
const ServiceWorkerWebpackPlugin = require('serviceworker-webpack-plugin'); module.exports = {
entry: {
app: './main.js'// Chunk app 的 JS 执行入口文件
},
output: {
filename: '[name].js',
publicPath: '',
},
module: {
rules: [
{
test: /\.css/,// 增加对 CSS 文件的支持
// 提取出 Chunk 中的 CSS 代码到单独的文件中
use: ExtractTextPlugin.extract({
use: ['css-loader'] // 压缩 CSS 代码
}),
},
]
},
plugins: [
// 一个 WebPlugin 对应一个 HTML 文件
new WebPlugin({
template: './template.html', // HTML 模版文件所在的文件路径
filename: 'index.html' // 输出的 HTML 的文件名称
}),
new ExtractTextPlugin({
filename: `[name].css`,// 给输出的 CSS 文件名称加上 Hash 值
}),
new ServiceWorkerWebpackPlugin({
// 自定义的 sw.js 文件所在路径
// ServiceWorkerWebpackPlugin 会把文件列表注入到生成的 sw.js 中
entry: path.join(__dirname, 'sw.js'),
}),
],
devServer: {
// Service Workers 依赖 HTTPS,使用 DevServer 提供的 HTTPS 功能。
https: true,
}
};

18、多页

AutoWebPlugin插件来配置多页
├── pages
│   ├── index
│   │   ├── index.css // 该页面单独需要的 CSS 样式
│   │   └── index.js // 该页面的入口文件
│   └── login
│   ├── index.css
│   └── index.js
├── common.css // 所有页面都需要的公共 CSS 样式
├── google_analytics.js
├── template.html
└── webpack.config.js
  • 所有单页应用的代码都需要放到一个目录下,例如都放在 pages 目录下;
  • 一个单页应用一个单独的文件夹,例如最后生成的 index.html 相关的代码都在 index 目录下,login.html 同理;
  • 每个单页应用的目录下都有一个 index.js 文件作为入口执行文件。

AutoWebPlugin 强制性的规定了项目部分的目录结构,在pages下,每一个文件夹就是一个目录。通过插件自动生成手动需要配置的两个html插件。

const { AutoWebPlugin } = require('web-webpack-plugin');

// 使用本文的主角 AutoWebPlugin,自动寻找 pages 目录下的所有目录,把每一个目录看成一个单页应用
const autoWebPlugin = new AutoWebPlugin('pages', {
template: './template.html', // HTML 模版文件所在的文件路径
postEntrys: ['./common.css'],// 所有页面都依赖这份通用的 CSS 样式文件
// 提取出所有页面公共的代码
commonsChunk: {
name: 'common',// 提取出公共代码 Chunk 的名称
},
}); module.exports = {
// AutoWebPlugin 会为寻找到的所有单页应用,生成对应的入口配置,
// autoWebPlugin.entry 方法可以获取到所有由 autoWebPlugin 生成的入口配置
entry: autoWebPlugin.entry({
// 这里可以加入你额外需要的 Chunk 入口
}),
plugins: [
autoWebPlugin,
],
};

template.html 模版文件如下:

<html>
<head>
<meta charset="UTF-8">
<!--在这注入该页面所依赖但没有手动导入的 CSS-->
<!--STYLE-->
<!--注入 google_analytics 中的 JS 代码-->
<script src="./google_analytics.js?_inline"></script>
<!--异步加载 Disqus 评论-->
<script src="https://dive-into-webpack.disqus.com/embed.js" async></script>
</head>
<body>
<div id="app"></div>
<!--在这注入该页面所依赖但没有手动导入的 JavaScript-->
<!--SCRIPT-->
<!--Disqus 评论容器-->
<div id="disqus_thread"></div>
</body>
</html>

在模版中生成

  • CSS 类型的文件注入到 所在的位置,如果 不存在就注入到 HTML HEAD 标签的最后;
  • JavaScrip 类型的文件注入到 所在的位置,如果 不存在就注入到 HTML BODY 标签的最后。
通过gulp来管理html,webapck来处理js也是解决多页的好方法
利用html-webpack-plugin 插件循环生成
// 引入插件
const HTMLWebpackPlugin = require("html-webpack-plugin");
// 引入多页面文件列表
const { HTMLDirs } = require("./config");
// 通过 html-webpack-plugin 生成的 HTML 集合
let HTMLPlugins = [];
// 入口文件集合
let Entries = {} // 生成多页面的集合
HTMLDirs.forEach((page) => {
const htmlPlugin = new HTMLWebpackPlugin({
filename: `${page}.html`,
template: path.resolve(__dirname, `../app/html/${page}.html`),
chunks: [page, 'commons'],
});
HTMLPlugins.push(htmlPlugin);
Entries[page] = path.resolve(__dirname, `../app/js/${page}.js`);
})

19、同构

构建服务端渲染

服务端渲染的代码要运行在nodejs环境,和浏览器不同的是,服务端渲染代码需要采用commonjs规范同时不应该包含除js之外的文件比如css。webpack配置如下:

module.exports = {
target: 'node',
entry: {
'server_render': './src/server_render',
},
output: {
filename: './dist/server/[name].js',
libraryTarget: 'commonjs2',
},
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
},
{
test: /\.(scss|css|pdf)$/,
loader: 'ignore-loader',
},
]
},
};

其中几个关键的地方在于:

target: 'node' 指明构建出的代码是要运行在node环境里

libraryTarget: 'commonjs2' 指明输出的代码要是commonjs规范

{test: /.(scss|css|pdf)$/,loader: 'ignore-loader'} 是为了防止不能在node里执行服务端渲染也用不上的文件被打包进去。

20、laoder与plugins插件编写

如果你的扩展是想对一个个单独的文件进行转换那么就编写loader剩下的都是plugin

其中对文件进行转换可以是像:

  • babel-loader把es6转换成es5
  • file-loader把文件替换成对应的URL
  • raw-loader注入文本文件内容到代码里去

编写loader非常简单,以comment-require-loader为例:

module.exports = function (content) {
return replace(content);
};

loader的入口需要导出一个函数,这个函数要干的事情就是转换一个文件的内容。

函数接收的参数content是一个文件在转换前的字符串形式内容,需要返回一个新的字符串形式内容作为转换后的结果,所有通过模块化倒入的文件都会经过loader。从这里可以看出loader只能处理一个个单独的文件而不能处理代码块

class EndWebpackPlugin {

constructor(doneCallback, failCallback) {
this.doneCallback = doneCallback;
this.failCallback = failCallback;
} apply(compiler) { 汇编者; 编辑者; 编纂者
// 监听webpack生命周期里的事件,做相应的处理
compiler.plugin('done', (stats) => {
this.doneCallback(stats);
});
compiler.plugin('failed', (err) => {
this.failCallback(err);
});
}

}

module.exports = EndWebpackPlugin;

loader的入口需要导出一个class, 在new EndWebpackPlugin()的时候通过构造函数传入这个插件需要的参数,在webpack启动的时候会先实例化plugin再调用plugin的apply方法,插件需要在apply函数里监听webpack生命周期里的事件,做相应的处理。

webpack plugin 里有2个核心概念:

Compiler: 从webpack启动到推出只存在一个Compiler,Compiler存放着webpack配置

Compilation: 由于webpack的监听文件变化自动编译机制,Compilation代表一次编译。

Compiler 和 Compilation 都会广播一系列事件。

webpack生命周期里有非常多的事件可以在event-hooks和Compilation里查到

21、常用loader与plugins

加载文件
  • raw-loader:把文本文件的内容加载到代码中去,在 3-20加载SVG 中有介绍。
  • file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件,在 3-19加载图片、3-20加载 SVG、4-9 CDN 加速 中有介绍。
  • url-loader:和 file-loader 类似,但是能在文件很小的情况下以 base64 的方式把文件内容注入到代码中去,在 3-19加载图片、3-20加载 SVG 中有介绍。
  • source-map-loader:加载额外的 Source Map 文件,以方便断点调试,在 3-21加载 Source Map 中有介绍。
  • svg-inline-loader:把压缩后的 SVG 内容注入到代码中,在 3-20加载 SVG 中有介绍。
  • node-loader:加载 Node.js 原生模块 .node 文件。
  • image-loader:加载并且压缩图片文件。
  • json-loader:加载 JSON 文件。
  • yaml-loader:加载 YAML 文件。
编译模版
  • pug-loader:把 Pug 模版转换成 JavaScript 函数返回。
  • handlebars-loader:把 Handlebars 模版编译成函数返回。
  • ejs-loader:把 EJS 模版编译成函数返回。
  • haml-loader:把 HAML 代码转换成 HTML。
  • markdown-loader:把 Markdown 文件转换成 HTML。
转换脚本语言
  • babel-loader:把 ES6 转换成 ES5,在3-1使用 ES6 语言中有介绍。
  • ts-loader:把 TypeScript 转换成 JavaScript,在3-2使用 TypeScript 语言中有遇到。
  • awesome-typescript-loader:把 TypeScript 转换成 JavaScript,性能要比 ts-loader 好。
  • coffee-loader:把 CoffeeScript 转换成 JavaScript。
转换样式文件
  • css-loader:加载 CSS,支持模块化、压缩、文件导入等特性。
  • style-loader:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS。
  • sass-loader:把 SCSS/SASS 代码转换成 CSS,在3-4使用 SCSS 语言中有介绍。
  • postcss-loader:扩展 CSS 语法,使用下一代 CSS,在3-5使用 PostCSS中有介绍。
  • less-loader:把 Less 代码转换成 CSS 代码。
  • stylus-loader:把 Stylus 代码转换成 CSS 代码。
检查代码
  • eslint-loader:通过 ESLint 检查 JavaScript 代码,在 3-16检查代码中有介绍。
  • tslint-loader:通过 TSLint 检查 TypeScript 代码。
  • mocha-loader:加载 Mocha 测试用例代码。
  • coverjs-loader:计算测试覆盖率。
其它
  • vue-loader:加载 Vue.js 单文件组件,在3-7使用 Vue 框架中有介绍。
  • i18n-loader:加载多语言版本,支持国际化。
  • ignore-loader:忽略掉部分文件,在3-11构建同构应用中有介绍。
  • ui-component-loader:按需加载 UI 组件库,例如在使用 antd UI 组件库时,不会因为只用到了 Button 组件而打包进所有的组件。
用于修改行为
  • define-plugin:定义环境变量,在4-7区分环境中有介绍。
  • context-replacement-plugin:修改 require 语句在寻找文件时的默认行为。
  • ignore-plugin:用于忽略部分文件。
用于优化
  • commons-chunk-plugin:提取公共代码,在4-11提取公共代码中有介绍。
  • extract-text-webpack-plugin:提取 JavaScript 中的 CSS 代码到单独的文件中,在1-5使用 Plugin 中有介绍。
  • prepack-webpack-plugin:通过 Facebook 的 Prepack 优化输出的 JavaScript 代码性能,在 4-13使用 Prepack 中有介绍。
  • uglifyjs-webpack-plugin:通过 UglifyES 压缩 ES6 代码,在 4-8压缩代码中有介绍。
  • webpack-parallel-uglify-plugin:多进程执行 UglifyJS 代码压缩,提升构建速度。
  • imagemin-webpack-plugin:压缩图片文件。
  • webpack-spritesmith:用插件制作雪碧图。
  • ModuleConcatenationPlugin:开启 Webpack Scope Hoisting 功能,在4-14开启 ScopeHoisting中有介绍。
  • dll-plugin:借鉴 DDL 的思想大幅度提升构建速度,在4-2使用 DllPlugin中有介绍。
  • hot-module-replacement-plugin:开启模块热替换功能。
其它
  • serviceworker-webpack-plugin:给网页应用增加离线缓存功能,在3-14 构建离线应用中有介绍。
  • stylelint-webpack-plugin:集成 stylelint 到项目中,在3-16检查代码中有介绍。
  • i18n-webpack-plugin:给你的网页支持国际化。
  • provide-plugin:从环境中提供的全局变量中加载模块,而不用导入对应的文件。
  • web-webpack-plugin:方便的为单页应用输出 HTML,比 html-webpack-plugin 好用。

22 webpack4

  • webpack 4 更快(速度提升98%)
  • 新增Mode选项,区分环境
  • 零配置以及默认值
  • 再见 CommonsChunkPlugin =》 新 API optimize.splitChunks
  • WebAssembly 支持
  • .mjs 支持

webpack的世界的更多相关文章

  1. 这本小书的目的是引导你进入 React 和 Webpack 的世界。他们两个都是非常有用的技术,如果同时使用他们,前端开发会更加有趣。

    https://fakefish.github.io/react-webpack-cookbook/index.html

  2. webpack初识!

    最近在使用webpack 感觉棒棒哒 下面这个简单的教程可以让你走入webpack的世界 欢迎使用webpack 这个小教程通过简单的例子来引导大家使用webpack 通过这些这篇文章你可以学到 如何 ...

  3. 2.2 webpack

    webpack 介绍 webpack 是什么 为什么引入新的打包工具 webpack 核心思想 webpack 安装 webpack 使用 命令行调用 配置文件 webpack 配置参数 entry ...

  4. 前端工程化基础-vue

    由浅入深支持更多功能 1.安装最新版本的node.js和NPM,并了解NPM基本用法. 2.创建一个目录demo.使用npm 初始化配置: npm init  ,执行后会有一系列选项,可按回车快速确认 ...

  5. 带你走进webpack世界,成为webpack头号玩家。

    最近朋友圈被<头号玩家>刷爆了,斯皮尔伯格一个资深电影导演,把对过去经典的致敬,对未来的憧憬浓缩在这一部电影中,可以说让观众燃了起来. 观望整个前端开发,不断的演化,发展迅速.前端开发从最 ...

  6. 基于webpack和vue.js搭建开发环境

    前言 在对着产品高举中指怒发心中之愤后,真正能够解决问题的是自身上的改变,有句话说的好:你虽然改变不了全世界,但是你有机会改变你自己.秉承着“不听老人言,吃亏在眼前”的优良作风,我还是决定玩火自焚. ...

  7. gulp + webpack + sass 学习

    笔记: new webpack.optimize.CommonsChunkPlugin 核心作用是抽离公共代码,chunks:['index.js','main.js'] 另一个作用就是单独生成一个j ...

  8. 学习 React(jsx语法) + es2015 + babel + webpack

    视频学习地址: http://www.jtthink.com/course/play/575 官方地址 https://facebook.github.io/react/ 神坑: 1.每次this.s ...

  9. webpack + vuejs 基本配置(一)

    开始之前 本文包含以下技术,文中尽量给与详细的描述,并且附上参考链接,读者可以深入学习: 1.webpack2.Vue.js3.npm4.nodejs —- 这个就不给连接了,因为上面的连接都是在你实 ...

随机推荐

  1. 从零开始学习前端开发 — 9、标签嵌套规则及CSS常用样式覆盖

    1. 块级元素可以包含内联元素或某些块级元素,但内联元素却不能包含块级元素,它只能包含其它的内联元素: <div><h1></h1><p></p& ...

  2. ==和equals详解+例子

    一开始遇见==和equals我也是分不清,后来看了很多博客,收益匪浅, 担心以后给忘了,所以写下这个,以后复习可以用. (有哪里写得不对的,希望可以留言帮忙改进,大家一起共同进步) 一.Java数据类 ...

  3. OKMX6Q LTIB编译

    因为在16.04上编译有许多解决不了的错误,最后还是在飞凌的12.04虚拟机上编译的. 按照手册<OKMX6X-S2-LTIB编译手册-V1.1-2016-08-18>进行到第8步时,出现 ...

  4. C#中的基元类型、值类型和引用类型

    C# 中的基元类型.值类型和引用类型 1. 基元类型(Primitive Type) 编译器直接支持的类型称为基元类型.基元类型可以直接映射到 FCL 中存在的类型.例如,int a = 10 中的 ...

  5. plist涉及到沙盒的一个问题

    http://blog.csdn.net/wowxavi1/article/details/8557271

  6. hdevelop (halcon)处理大分辨率图像问题

    HALCON 的ide有2种模式:hdevelop 和hdevelop xl hdevelop 适用于普通分辨率的图像,小于等于 32k x 32k : hdevelop xl适用于大分辨率的图像,大 ...

  7. AF_INET 和PF_INET区别;AF_LOCAL PF_LOCAL 区别.

    从字面理解: AF_INET = Address Format, Internet = IP Addresses PF_INET = Packet Format, Internet = IP, TCP ...

  8. 频繁更换ip会影响SEO优化吗?

    网站更换ip会不影响SEO的效果,其实网站更换ip是正常的(但不能频繁更换),搜索引擎抓取是根据网站的域名进行的,不是根据ip来抓取你的网站.在短时间内更换IP对SEO的效果并没有很大的影响. 如果是 ...

  9. Intellij-创建Maven项目速度慢

    原因: IDEA根据maven archetype的本质,其实是执行mvn archetype:generate命令,该命令执行时,需要指定一个archetype-catalog.xml文件. 该命令 ...

  10. CSS深入理解学习笔记之overflow

    1.Overflow基本属性 overflow:visible(默认)/hidden/scroll/auto/inherit; visible:超出部分可见. hidden:超出部分隐藏. scrol ...