webpack学习笔记
1 entry: string|Array
module.exports = {
entry: './path/to/my/entry/file.js' //entry:['./a.js','./b.js']如果是个数组,会按顺序打包到一个文件里面
};
module.exports = {
entry: {
app: './src/app.js',
vendors: './src/vendors.js' //多个入口文件对应多个output输出文件
}
};
2 output
const path = require('path');
module.exports = {
output: {
path:path.resolve(__dirname, 'dist'),//打包后的文件存放的地方
filename: "bundle.js",//打包后输出文件的文件名
},
publicPath:'http:ifchange.com' //css或者html用到相对路径时,在生产环境,会使用cdn前缀,加上publicPath不会有这个问题
}
module.exports = {
output: {
filename: '[name].[hash:7].js', //如果配置创建了多个单独的 "chunk",则应该使用占位符(substitutions)来确保每个文件具有唯一的名称。
//取7位hash值;文件更新之后生成不一样的hash值,防止缓存
path: __dirname + '/dist'
}
}
3 loader
loader 让 webpack 能够去处理那些非 JavaScript 文件
- 识别出应该被对应的 loader 进行转换的那些文件。(使用 test 属性)
- 转换这些文件,从而使其能够被添加到依赖图中(并且最终添加到 bundle 中)(use 属性)
在你的应用程序中,有三种使用 loader 的方式:
- 配置(推荐):在 webpack.config.js 文件中指定 loader。
- 内联:在每个 import 语句中显式指定 loader。
- CLI:在 shell 命令中指定它们。
//配置
module.exports = {
...
module: {
rules: [
{
test: /\.css$/, //里面包含两个必须属性:test 和 use
use: [ //数组
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
modules: true
}
}
]
}
]
}
}
//内联 使用 ! 将资源中的 loader 分开。分开的每个部分都相对于当前目录解析。
import Styles from 'style-loader!css-loader?modules!./styles.css'
//include 匹配以下路径文件
//exclude 排除以下路径文件
//options loader的配置参数
//oneof 数组,当规则匹配时,只使用第一个匹配规则。
//parser
parser: {
amd: false, // 禁用 AMD
commonjs: false, // 禁用 CommonJS
system: false, // 禁用 SystemJS
harmony: false, // 禁用 ES2015 Harmony import/export
requireInclude: false, // 禁用 require.include
requireEnsure: false, // 禁用 require.ensure
requireContext: false, // 禁用 require.context
browserify: false, // 禁用特殊处理的 browserify bundle
requireJs: false, // 禁用 requirejs.*
node: false, // 禁用 __dirname, __filename, module, require.extensions, require.main 等。
node: {...} // 在模块级别(module level)上重新配置 node 层(layer)
}
4 plugin
插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量,你只需要 require() 它,然后把它添加到 plugins 数组中。多数插件可以通过选项(option)自定义。你也可以在一个配置文件中因为不同目的而多次使用同一个插件,这时需要通过使用 new 操作符来创建它的一个实例。
webpack 插件是一个具有 apply 属性的 JavaScript 对象。apply 属性会被 webpack compiler 调用,并且 compiler 对象可在整个编译生命周期访问
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
const webpack = require('webpack'); // 用于访问内置插件
const path = require('path');
...
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var DashboardPlugin = require('webpack-dashboard/plugin');
module.exports = {
module: {
plugins: [
// build optimization plugins
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: 'vendor-[hash].min.js',
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
drop_console: false,
}
}),
new ExtractTextPlugin({
filename: 'build.min.css',
allChunks: true,
}),
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
// compile time plugins
new webpack.DefinePlugin({
'process.env.NODE_ENV': '"production"', //设置全局环境变量
}),
// webpack-dev-server enhancement plugins
new DashboardPlugin(),
new webpack.HotModuleReplacementPlugin(),
]
}
}
5 模块解析
import "module/lib/file";
如果路径指向一个文件:
- 如果路径具有文件扩展名,则被直接将文件打包。
- 否则,将使用 [resolve.extensions] 选项作为文件扩展名来解析,此选项告诉解析器在解析中能够接受哪些扩展名(例如 .js, .jsx)。
如果路径指向一个文件夹
- package.json 文件中的 main 字段返回一个有效路径,在文件夹下找到这个文件
- 如果 package.json 文件不存在或者 package.json 文件中的 main 字段没有返回一个有效路径,则按照顺序查找 resolve.mainFiles 配置选项中指定的文件名,看是否能在 import/require 目录下匹配到一个存在的文件名。
- 文件扩展名通过 resolve.extensions 选项采用类似的方法进行解析。
6 resolve
module.exports = {
resolve: {
extensions: [".js", ".json", ".jsx", ".css"],//resolve一些在import文件时不带文件扩展名的表达式
alias: {
'tob': path.join(__dirname, './app/static/tob/'), //对路径起别名
},
}
}
7 devServer
module.exports = {
port: 9001,
contentBase: './dist',
public: 'http://localhost:9001',
compress:true,//为所有服务启用gzip压缩,在response header里Content-Encoding:gzip
before(app) { //提供在服务器内部的所有其他中间件之前执行定制中间件的功能,当其他服务器获取dist目录下面的资源,设置允许所有域名获取
app.use(function (req, res, next) {
res.set('Access-Control-Allow-Origin', '*');
next();
});
}
}
8 devtool
有很多种模式,
module.exports = {
devtool: 'source-map',
}
source-map
//# sourceMappingURL=index.js.map 在bundle文件尾部生成一个注释
与此同时,你会发现你的 output 目录下多了一个 index.js.map ,这里面有bundle文件的行,列,,,信息
- 使用 cheap 模式可以大幅提高 souremap 生成的效率。大部分情况我们调试并不关心列信息,而且就算 sourcemap 没有列,有些浏览器引擎(例如 v8) 也会给出列信息。
- 使用 eval 方式可大幅提高持续构建效率。官方文档提供的速度对比表格可以看到 eval 模式的编译速度很快。
- 使用 module 可支持 babel 这种预编译工具(在 webpack 里做为 loader 使用)。
- 使用 eval-source-map 模式可以减少网络请求。这种模式开启 DataUrl 本身包含完整 sourcemap 信息,并不需要像 sourceURL 那样,浏览器需要发送一个完整请求去获取 sourcemap 文件,这会略微提高点效率。而生产环境中则不宜用 eval,这样会让文件变得极大。
9 常用plugin
const HtmlWebpackPlugin = require('html-webpack-plugin'); //生成html模板
new HtmlWebpackPlugin({
inject: true,//生成的script标签在body底部
filename: path.join(__dirname, 'app/view/index.html'),//指定文件名,可以获取HtmlWebpackPlugin的配置options
template: path.join(__dirname, 'app/static/index.html'),//指定模板 由模板生成文件
}),
const ExtractTextPlugin = require("extract-text-webpack-plugin");
new ExtractTextPlugin("css/[name].[contenthash:8].css") //将所有style提取到css文件夹中生成对应的文件
const CleanWebpackPlugin = require('clean-webpack-plugin');//清楚指定路径插件缓存
new CleanWebpackPlugin(distPath)
const webpack = require('webpack');
new webpack.optimize.CommonsChunkPlugin({
name: "commons",//entry里面的块名
filename: "js/commons.[hash:8].js"//将公共块生成一个文件,提高性能
}),
new webpack.DefinePlugin({ //定义全局变量,
"process.env.NODE_ENV": JSON.stringify(ENV)//JSON.stringify变为字符串
}),
new webpack.HotModuleReplacementPlugin() //热模块替换,
HMRnew webpack.optimize.UglifyJsPlugin({ //使用 UglifyJS 去压缩你的JavaScript代码
sourceMap: true,
beautify: false,
comments: false,
compress: {
warnings: false,
collapse_vars: true,
reduce_vars: true
}
}),
cross-env
cross-env这使得你可以有一个单一的命令,而不必担心为平台设置或使用环境变量。只要像在POSIX系统上运行一样cross-env进行设置,就可以正确设置。
npm install --save-dev cross-env
{
"scripts": {
"build": "cross-env NODE_ENV=production webpack --config build/webpack.config.js"
}
}
webpack --progress --colors //显示进度,改变颜色