Webpack知识汇总
介绍
webpack把任何一个文件都看成是一个模块,模块间可以相互依赖(require or import),webpack的功能就是把相互依赖的文件打包在一起。webpack本身只能处理原生的Javascript模块,但是它支持的各种loader转换器可以将各种类型的资源转换成javascript模块。这样任何资源都可以成为webpack可以处理的模块。同时,webpack还有丰富的插件plugin, 可以完成例如js,css的压缩,公共依赖模块的提取和注入,甚至利用模板对html进行动态拼接等功能。同时,webpack使用commonjs规范(require),支持es6语法(import)的编译。官方网站:https://doc.webpack-china.org/
深入浅出webpack系列教程:http://www.cnblogs.com/ghostwu/p/7499237.html
1.安装webpack
npm install webpack -g //全局安装
npm install webpack --save-dev //开发环境
2 使用
在package.json文件同级目录中创建一个webpack.config.js文件,这个文件是webpack的配置文件。
const webpack = require('webpack'); const BrowserSyncPlugin = require('browser-sync-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { //页面入口文件配置 entry: { polyfills: './src/main/webapp/app/polyfills', global: './src/main/webapp/content/scss/global.scss', main: './src/main/webapp/app/app.main' }, //入口文件输出配置 output: { path: utils.root('build/www'), filename: 'app/[name].bundle.js', chunkFilename: 'app/[id].chunk.js' }, module: { //加载器配置 loaders: [ { test: /\.css$/, loader: 'style-loader!css-loader' }, { test: /\.js$/, loader: 'jsx-loader?harmony' }, { test: /\.scss$/, loader: 'style!css!sass?sourceMap'}, //图片文件使用 url-loader 来处理,小于8kb的直接转为base64 { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'} ] }, //解析模块路径时的配置 resolve: { root: 'E:/github/flux-example/src', //绝对路径,查找module的话从这里开始查找 extensions: ['', '.js', '.json', '.scss'], //自动扩展文件后缀名,意味着我们require模块可以省略不写后缀名 alias: { //别名配置,,方便后续直接引用别名,无须多写长长的地址 AppStore : 'js/stores/AppStores.js', ////后续直接 require('AppStore') 即可 ActionType : 'js/actions/ActionType.js', AppAction : 'js/actions/AppAction.js' } }, //插件项 plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', chunks: ['main'], minChunks: (module) => utils.isExternalLib(module) }), new BrowserSyncPlugin({ host: 'localhost', port: 9000, proxy: { target: 'http://localhost:9060', ws: true } }, { reload: false }), new HtmlWebpackPlugin({ template: './src/main/webapp/index.html', chunksSortMode: 'dependency', inject: 'body' }) ], };
webpack.config.js配置参数 (详细说明:https://zhuanlan.zhihu.com/p/21346555)
devtool: 'eval-source-map' //webpack
就可以在打包时为我们生成的source maps
,这为我们提供了一种对应编译文件和源文件的方法,使得编译后的代码可读性更高,也更容易调试
在webpack
的配置文件中配置source maps
,需要配置devtool
,它有以下四种不同的配置选项,各具优缺点,描述如下:
devtool选项 | 配置结果 |
---|---|
source-map |
在一个单独的文件中产生一个完整且功能完全的文件。这个文件具有最好的source map ,但是它会减慢打包速度; |
cheap-module-source-map |
在一个单独的文件中生成一个不带列映射的map ,不带列映射提高了打包速度,但是也使得浏览器开发者工具只能对应到具体的行,不能对应到具体的列(符号),会对调试造成不便; |
eval-source-map |
使用eval 打包源文件模块,在同一个文件中生成干净的完整的source map 。这个选项可以在不影响构建速度的前提下生成完整的sourcemap ,但是对打包后输出的JS文件的执行具有性能和安全的隐患。在开发阶段这是一个非常好的选项,在生产阶段则一定不要启用这个选项; |
cheap-module-eval-source-map |
这是在打包文件时最快的生成source map 的方法,生成的Source Map 会和打包后的JavaScript 文件同行显示,没有列映射,和eval-source-map 选项具有相似的缺点; |
正如上表所述,上述选项由上到下打包速度越来越快,不过同时也具有越来越多的负面作用,较快的打包速度的后果就是对打包后的文件的的执行有一定影响。
对小到中型的项目中,eval-source-map
是一个很好的选项,再次强调你只应该开发阶段使用它。
cheap-module-eval-source-map
方法构建速度更快,但是不利于调试,推荐在大型项目考虑时间成本时使用。
devServer: { //设置 webpack-dev-server 的相关配置,devServer的更多配置信息参考https://webpack.js.org/configuration/dev-server/
contentBase: './build/www', //本地服务器所加载的页面所在的目录
proxy: [{
context: [],
target: 'http://127.0.0.1:8080',
secure: false,
ws: true/false
}],
historyApiFallback: true,//不跳转
inline: true, //实时刷新
hot: true
},
devserver的配置选项 | 功能描述 |
---|---|
contentBase | 默认webpack-dev-server会为根文件夹提供本地服务器,如果想为另外一个目录下的文件提供本地服务器,应该在这里设置其所在目录(本例设置到“public"目录) |
port | 设置默认监听端口,如果省略,默认为”8080“ |
inline | 设置为true ,当源文件改变时会自动刷新页面 |
historyApiFallback | 在开发单页应用时非常有用,它依赖于HTML5 history API,如果设置为true ,所有的跳转将指向index.html |
entry: {}
output: {
path: '',
filename: '',
publicPath: '',
chunkFilename: ''
},
resolve: {
alias: [], //设置模块别名
root: '', //包含你模块的目录(必须是绝对路径),通常是一个目录数组,这个设置应该被用于添加个人目录到webpack查找路径里.
modulesDirectories:[], //解析目录名的一个数组到当前目录以及先前的目录,并且是查找模块。这个函数和node怎么找到node_modules很像。比如如果值为 // // ["mydir"],webpack会查找“./mydir”, “../mydir”, “../../mydir”,等等。默认: ["web_modules", "node_modules"]
extensions: [] //解析模块的拓展名的数组。设置这个选项将会重写默认值,这意味着webpack不再试着用默认的拓展名解析模块,如果你希望模块加载的时候带着他们的拓展名也可以得到正确额解析(比如require('./somefile.ext')),你需要在你的数组里添加一个空字符串。如果你希望模块加载不带拓展名(比如require('underscore'))可以解析为“.js”的拓展名。你必须在数组里包含".js".
},
externals: [], // 指定的依赖不会被webpack解析,但会成为bundle里的依赖。output.libraryTarget.决定着依赖的类型。值是对象,字符串,函数,正则,数组都会被接受。
stats: {}
module: {
rules(或loaders): [
{
test: string, //必须满足的条件,正则表达式(测试绝对路径),包含绝对路径的字符串
enforce: string,
loaders: ['','',...] , //多个loader
loader: string, //用“!”隔开多个loader
exclude: ['','',...], //不满足的条件
include: ['','',...] //必须满足条件
},
{ test: /(\.jsx|\.js)$/, use: { loader: "babel-loader" }, exclude: /node_modules/ },
{
test: /\.css$/,
use: [
{
loader: "style-loader"
}, {
loader: "css-loader",
options: { modules: true }
},
{ loader: "postcss-loader" }
]
}
],
preLoaders: [],
postLoaders: [],
noParse: []
},
Loaders需要单独安装并且需要在webpack.config.js
中的modules
关键字下进行配置,Loaders的配置包括以下几方面:
test
:一个用以匹配loaders所处理文件的拓展名的正则表达式(必须)loader
:loader的名称(必须)include/exclude
:手动添加必须处理的文件(文件夹)或屏蔽不需要处理的文件(文件夹)(可选);query
:为loaders提供额外的设置选项(可选)
plugins: []
webpack命令参数:
$ webpack --config XXX.js //使用另一份配置文件(比如webpack.config2.js)来打包 $ webpack --watch //监听文件是否有改变,有改变就会重新编译有改变的文件 $ webpack -p//压缩混淆脚本 $ webpack -d//生成map映射文件,告知哪些模块被最终打包到哪里了 $ webpack --progress //显示打包过程进度条 $ webpack --color //配置打包输出颜色显示
3 各种插件
NoErrorsPlugin插件:该插件可以在webpack打包过程中遇到错误时跳过,不终止webpack进程~
PrefetchPlugin插件:该插件的作用是当一个模块还未被require之前,提前解析和建立一个对该插件的请求,可以起到一定的优化打包时间的效果。其中两个参数第一个是模块的绝对路径,第二个是对模块的请求字符串,eg.
new webpack.PrefetchPlugin(__dirname +”/node_modules”,”react/react.js”)
HotModuleReplacementPlugin插件:热更新所需插件,实现模块变动部分的替代而不重新刷新页面,有效提高调试时间
HtmlWebpackPlugin插件:可以为你生成一个自动引用你打包后的JS文件的新index.html
BrowserSyncPlugin
插件:它当你的webpack或webpack-dev-server 执行完全后,自动为你的应用打开浏览器~
new BrowserSyncPlugin({ host: 'localhost', port: 9000, // 代理服务器配置 proxy: { target: 'http://localhost:9060', ws: true } }, { reload: false })
Webpack.DefinePlugin插件: 可以定义编译时的全局变量,有很多库(React, Vue等)会根据 NODE_ENV 这个变量来判断当前环境。为了尽可能减少包大小,在生产环境中要定义其为 JSON.stringify(“production”)
plugins: [ new webpack.DefinePlugin({ "process.env.NODE_ENV": "development" }) ]
Webpack.optimize.CommonsChunkPlugin插件:它用于提取多个入口文件的公共脚本部分,然后生成一个 common.js 来方便多页面之间进行复用
具体使用方法见http://www.jianshu.com/p/2b81262898a4
Webpack.ContextReplacementPlugin插件:
Webpack.ProvidePlugin插件:定义一些在import时能自动引入的变量,如定义了 $: 'jquery'
后,可以在文件中直接使用$
,webpack可以自动帮你加上 var $ = require('jquery')
。
Webpack.LoaderOptionsPlugin插件
Webpack.NoEmitOnErrorsPlugin插件:
Webpack.NamedModulesPlugin插件
Webpack.WatchIgnorePlugin插件:
FaviconsWebpackPlugin插件:该插件则可以为不同的设备自动生成超过30种的favicon(它们的来源都是同一张图片)
CopyWebpackPlugin插件:
MergeJsonWebpackPlugin插件:
StringReplacePlugin插件:
WebpackNotifierPlugin插件:
writeFilePlugin插件:
ExtractTextPlugin: 分离CSS和JS文件。
new ExtractTextPlugin("style.css")
DedupePlugin插件:可在production环境下帮助删除重复或相似文件,可以有效减少文件大小(用于打包文件优化,建议使用在生产环境)
OccurrenceOrderPlugin插件:根据出现次数为每一个模块或者chunk设置id,经常使用的模块则会获取到较短的id(和前缀树类似),这可以使id可预测并有效减少文件大小,建议使用在生产环境中~
NpmInstallPlugin插件:这个并未在webpack官网的插件列表内提到过,但是个人认为它通过自动帮助我们安装依赖而提升了我们的开发效率,https://github.com/ericclemmons/npm-install-webpack-plugin,具体效果可以看下官网~
plugins: [ new NpmInstallPlugin({ // Use --save or --save-dev dev: false, // Install missing peerDependencies peerDependencies: true, }); ],
webpack.optimize.UglifyJsPlugin插件: 压缩js
new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false, // Drop `console` statements drop_console: true } })
4 模块
webpack-merge: 可以把分开配置的config合并,分开生产环境和调试环境
const merge = require('webpack-merge'); const commonConfig= {}; module.exports = merge(commonConfig, {});
webpack-validator: 验证我们的config是否正确
const merge = require('webpack-merge'); const validate = require('webpack-validator'); const commonConfig = {}; const config = merge(commonConfig, {}); module.exports = validate(config);
source-map:init时会慢,之后rebuild快
devtool: 'source-map',