webpack 简述
按照webapck 官网所说,webpack 是一个模块打包工具(webpack is a module bundler)。它接收依赖的模块,将其转化为静态资源。
webpack 与众不同的三大核心概念
Code Spliting
Loaders
Plugin System
配置(configuration)
CLI
如果使用 CLI,webpack 将会读取 webpack.config.js 文件(或者通过–config 选项传递的文件),这个文件需要暴露这样的配置对象:
module.exports = {
// configuration
};
常见 CLI option
1)开发环境简写 -d
等价于:–debug –devtool source-map –output-pathinfo
2)生产环境简写 -p
等价于:–optimize-minimize –optimize-occurrence-order
3)监视模式 –watch
4)配置文件 –config example.config.js
指定新的配置文件,而不是默认的 webpack.config.js
5)常见的显示选项
–progress
–display-chunks
–display-reasons
–display-error-details
–display-modules
–display-exclude
可以通过 script 来定义脚本,然后 npm run 命令名。
** 一个简单的配置对象,注意不是 json,只是简单的 object **
{
context: __dirname + "/app",
entry: "./entry",
output: {
path: __dirname + "/dist",
filename: "bundle.js"
}
}
context
context:根目录(绝对路径!)。可以认为是文件查找的上下文。默认 process.cwd()
entry
entry:包的入口点,有三种形式
一个 string
一个由多个 string 构成的 array
一个 object(多页面场景下),key 是 chunk 的 name,value 可以是 string 或者 array
output
output.filename
不要在这里指定绝对路径
多入口情况下使用占位符
[name] 模块名称
[hash] 模块编译后的(整体)Hash 值
[chunkhash] 分片的 Hash 值,可以认为是文件的版本号,也可以认为是文件的 MD5 值,在静态资源的版本管理中非常有用
output.path
output.publicPath
指定 public URL 地址,当我们要将 output 的文件放在不同的域名或者 CDN 上时十分有用
module
module.loaders 一个自动应用的 loaders 的数组,每项(item)可以有这些属性:
test: A condition that must be met
exclude: A condition that must not be met
include: An array of paths or files where the imported files will be transformed by the loader
loader: A string of “!” separated loaders
loaders: An array of loaders as string
resolve
resolve.alias
模块别名定义,方便后续直接引用别名
resolve: {
alias: { AppStore : 'js/stores/AppStores.js',//之后直接 require('AppStore')
}
}
resolve.root
包含你模块的目录(绝对路径),也可以是一个目录数组,这个设置应该被用于添加个人目录到 webpack 查找路径里
必须是个绝对路径,不要这样写./app/modules
resolve.modulesDirectories
这是一个目录数组,用来解析到当前目录以及祖先目录和查找模块。这个函数的工作原理和 node 如何查找 node_modules 目录很像。比如如果值为[“mydir”],webpack 会查找“./mydir”, “../mydir”, “../../mydir”等等
默认: [“web_modules”, “node_modules”]
resolve.extensions
一个用来解析模块的拓展名数组。比如,为了发现一个 CoffeeScript 文件,你的数组里应该包含字符串”.coffee”
默认: [“”, “.webpack.js”, “.web.js”, “.js”]
注意:设置这个选项将会重写默认值
externals
指定不该被 webpack 打包的模块,但是在打包后的包中仍然保留了请求。
我们可以通过它来暴露全局变量,而在需要的文件中直接 require 或 import 就可以了
externals: {
jquery: 'jQuery';
}
plugins
给编译器添加额外的插件
各种 loaders
webpack 可以使用 loader 来预处理文件。这允许你打包除 JavaScript 之外的任何静态资源。你可以使用 Node.js 来很简单地编写自己的 loader。
loader 的使用有三种方法,分别是:
在 require 中显式指定,即上面看到的用法
在配置项(webpack.config.js)中指定
在命令行中指定
转换 ES6 语法或 React 语法
通过 presets 选择 ES6 特性,也可以在 package.json 中指定
解决 babel-loader 处理 React 的 preset 问题:npm i –save-dev babel-preset-react
2)css 相关
style-loader 将模块的导出作为样式添加到 DOM 中
css-loader 解析 CSS 文件后,使用 import 加载,并且返回 CSS 代码,可以在 loader 后面?modules 以支持CSS Module
less-loader 加载和转译 LESS 文件
sass-loader 加载和转译 SASS/SCSS 文件,须先安装 node-sass,windows 可能安装出错,使用 cnpm i node-sass –save-dev 或者如下:
npm install –save-dev node-sass –registry=https://registry.npm.taobao.org –disturl=https://npm.taobao.org/dist –sass-binary-site=http://npm.taobao.org/mirrors/node-sass
postcss-loader 使用 PostCSS 加载和转译 CSS/SSS 文件,可以进行 autoprefixer
CSS 中@import 另一个 CSS 怎么处理?(非 SASS、LESS)
给 css-loader 添加参数
loader: 'style-loader!css-loader?importLoaders=1!postcss-loader'
3)模板相关
html-loader 导出 HTML 为字符串,需要引用静态资源
jade-loader 加载 Jade 模板并返回一个函数
markdown-loader 将 Markdown 转译为 HTML
handlebars-loader 将 Handlebars 转换为 HTML
ejs-loader 将 underscore 模板转换为 HTML
4)图片相关
file-loader
url-loader 与 file-loader,但如果文件小于限制,可以返回 data URL
image-loader 压缩图片
components 模板引用相对路径图片不会替换?
可以使用绝对路径或者这样写 src=”${require(‘../../assets/bg.png’)}”
5)bundle-loader
bundle-loader 是一个用来在运行时异步加载模块的 loader。可以用来做代码分割
6)exports-loader
可以从模块中导出变量。
在实际使用中,用 exports-loader 最多的场景是将某些不支持模块化规范的模块所声明的全局变量作为模块内容导出。
如下可以导出全局变量 Hello,exports-loader 还可以支持同时导出多个变量,例如 exports?HELLO,WORLD
module.exports = {
module: {
loaders: [{ test: require.resolve('./hello'), loader: 'exports?Hello' }],
},
};
7)imports-loaders
用于向一个模块的作用域内注入变量(Can be used to inject variables into the scope of a module)
8)expose-loader
把一个模块导出并付给一个全局变量
require('expose?libraryName!./file.js');
// Exposes the exports for file.js to the global context on property "libraryName".
// In web browsers, window.libraryName is then available.
各种 plugins
参数:
template html 模板地址,默认为 webpack.config.js 所在的目录
inject 插入位置
title
date 等
2)CommonsChunkPlugin
将多个入口起点之间共享的公共模块,生成为一些 chunk,并且分离到单独的 bundle 中,例如,1vendor.bundle.js 和 app.bundle.js
3)ExtractTextWebpackPlugin
从 bundle 中提取文本(CSS)到分离的文件(app.bundle.css)
4)ProvidePlugin
ProvidePlugin 可以将模块作为一个变量,被 webpack 在其他每个模块中引用。只有你需要使用此变量的时候,这个模块才会被 require 进来。多数之前遗留的模块,会依赖于已存在的某些特定全局变量,比如 jQuery 插件中的$或者jQuery。在这种场景,你可以在每次遇到全局标识符$的时候,在 webpack 中预先设置 var $ = require(“jquery”)。
module.exports = {
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
}),
],
};
Environment flags
windows 下使用 cross-env 的 npm 包兼容处理,可以在 package.json 设置如下:
"scripts": {
"clear": "rm -rf build&& mkdir build",
"start": "npm run clear&& cross-env NODE_ENV=development webpack-dev-server --host 0.0.0.0 --devtool eval --progress --color --profile",
"deploy": "npm run clear&& cross-env NODE_ENV=production webpack -p --progress"
}
webpack.config.js
var isProduction = process.env.NODE_ENV === 'production';
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(process.env.NODE_ENV || 'development'),
},
}),
];
Code splitting(代码分割)
使用 require.ensure
// main.js
require.ensure(['./a'], function (require) {
var content = require('./a');
document.open();
document.write('<h1>' + content + '</h1>');
document.close();
});
// a.js
module.exports = 'Hello World';
require.ensure 告诉 Webpack,./a.js 应该从 bundle.js 分离并且打包成一个单独的文件
注意 require.ensure 只会加载模块而不会去解析
也可以用 bundle-loader 进行代码分割
// main.js
// Now a.js is requested, it will be bundled into another file
var load = require('bundle-loader!./a.js');
// To wait until a.js is available (and get the exports)
// you need to async wait for it.
load(function (file) {
document.open();
document.write('<h1>' + file + '</h1>');
document.close();
});
vendor chunk
可以用 CommonsChunkPlugin 插件将公共库(vendor)打包成一个单独的文件
var webpack = require('webpack');
module.exports = {
entry: {
app: './main.js',
vendor: ['jquery'],
},
output: {
filename: 'bundle.js',
},
plugins: [
new webpack.optimize.CommonsChunkPlugin(
/* chunkName= */ 'vendor',
/* filename= */ 'vendor.js'
),
],
};
模块热替换(Hot Module Replacement)
npm i webpack-dev-server --save-dev