什么是webpack
webpack是一个模块打包器,包(bundle)就是一个js文件,它把一堆资源合并在一起,以便在同一个文件请求中发回给客户端,webpack还能处理一些浏览器不能直接运行的拓展语言,如Scss,typeScript等。webpack是基于配置型的构建工具,它把整个项目作为一个整体,通过一个给定的主文件(如index.js),从这个主文件开始找到项目所有的依赖文件,使用loaders处理它们,最终打包为一个或多个浏览器可识别的js文件。
webpack和gulp的区别
webpack:作为一个智能解析器,几乎可以处理任何一个第三方的库,无论是commonjs,amd还是普通的js文件,甚至加载依赖的时候可以动态表达式。webpack是一种预编译的解决方案,不需要在浏览器中加载解释器,而且不管是AMD/CMD/ES6风格的模块化,它都认识,并且能编译成浏览器认识的JS。webpack是一种模块化的解决方案,webpack在很多场景下可以替代gulp/grunt类的工具
gulp:在一个配置文件中,指明对某些文件进行类似编译、组合、压缩等任务的具体步骤,工具之后可以在自动替你完成这些任务。gulp是一个能够优化前端的开发流程的工具。
使用webpack
项目环境
//全局安装npm install -g webpack//安装到项目里npm install --save-dev webpack
如果项目中没有package.json这个文件,可以通过以下指令创建:
npm init
一个简单的配置文件
webpack.config.js
// 一个常见的`webpack`配置文件const webpack = require(‘webpack‘);const HtmlWebpackPlugin = require(‘html-webpack-plugin‘);const ExtractTextPlugin = require(‘extract-text-webpack-plugin‘);module.exports = { ???????entry: __dirname + "/app/main.js", //已多次提及的唯一入口文件 ???????output: { ???????????path: __dirname + "/build", ?//打包后的文件存放的地方 ???????????filename: "bundle-[hash].js" ?//打包后输出文件的文件名 ???????}, ???????devtool: ‘none‘, ???????devServer: { ???????????contentBase: "./public", //本地服务器所加载的页面所在的目录 ???????????historyApiFallback: true, //不跳转 ???????????inline: true, ???????????hot: true ???????}, ???????module: { ???????????rules: [{ ???????????????????test: /(\.jsx|\.js)$/, ???????????????????use: { ???????????????????????loader: "babel-loader" ???????????????????}, ???????????????????exclude: /node_modules/ ???????????????}, { ???????????????????test: /\.css$/, ???????????????????use: ExtractTextPlugin.extract({ ???????????????????????fallback: "style-loader", ???????????????????????use: [{ ???????????????????????????loader: "css-loader", ???????????????????????????options: { ???????????????????????????????modules: true, ???????????????????????????????localIdentName: ‘[name]__[local]--[hash:base64:5]‘ ???????????????????????????} ???????????????????????}, { ???????????????????????????loader: "postcss-loader" ???????????????????????}], ???????????????????}) ???????????????} ???????????} ???????] ???}, ???plugins: [ ???????new webpack.BannerPlugin(‘版权所有,翻版必究‘), ???????new HtmlWebpackPlugin({ ???????????template: __dirname + "/app/index.tmpl.html" //new 一个这个插件的实例,并传入相关的参数 ???????}), ???????new webpack.optimize.OccurrenceOrderPlugin(), ???????new webpack.optimize.UglifyJsPlugin(), ???????new ExtractTextPlugin("style.css") ???]};
配置分析
一 entry和output
entry用来定义入口文件,可以是字符串或数组或对象
1.字符串:
module.exports = { ?entry: ‘./main.js‘};
2.数组:除了main.js作为入口js之外,还有一个是用来配置webpack提供的一个静态资源服务器webpack-dev-server,它会监控项目中每个文件的变化,实时构建,并自动刷新页面。
module.exports = { ?entry: [ ???‘webpack/hot/only-dev-server‘, ???‘./main.js‘ ?]};
3.对象:将不同的文件按需构建,按需使用
module.exports = { ?entry: { ???a: ‘./a.js‘, ???b: ‘./b.js‘ ?}};
output用于定义构建后的文件的输出,是个对象,其中包含了path和filename
module.exports = { ?output: { ???path: ‘./build‘, ???filename: ‘bundle.js‘ ?}};
二 devtool
devtool属性可以配置调试代码的方式,有多种调试方式,一般只在开发时使用,生产环境下应该将值设置为false。常用值有两个:
eval: 可以设断点调试,不显示信息,每个js模块代码用eval()执行,并且在生成的每个模块代码尾部加上注释,不 会生成.map文件。
source-map: 可以设断点调试,不显示列信息,生成相应的.Map文件,并在合并后的代码尾部加上注释//# sourceMappingURL=**.js.map,可以看到模块代码并没有被eval()包裹,此种模式并没有将调试信息放入打 包后的代码中,保持了打包后代码的简洁性.
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选项具有相似的缺点; |
上述选项由上到下打包速度越来越快,不过同时也具有越来越多的负面作用,较快的打包速度的后果就是对打包后的文件的的执行有一定影响。cheap-module-eval-source-map推荐在大型项目考虑时间成本时使用,对小到中型的项目中,eval-source-map是一个很好的选项。
三 devserver
如果想让你的浏览器监听你的代码修改,并自动刷新显示修改后的结果,webpack提供了一个可选的本地开发服务器,这个本地服务器基于node.js构建,可以实现你想要的这些功能,不过这是一个单独的组件,在webpack进行配置之前需要单独安装它作为项目依赖。
npm install --save-dev webpack-dev-server
devserver有一些配置选项,可以参考如下的配置:
devserver的配置选项 | 功能描述 |
contentBase | 默认webpack-dev-server会为根文件夹提供本地服务器,如果想为另外一个目录下的文件提供本地服务器,应该在这里设置其所在目录 |
port | 设置默认监听端口,如果省略,默认为”8080“ |
inline | 设置为true,当源文件改变时会自动刷新页面 |
historyApiFallback | 在开发单页应用时非常有用,它依赖于HTML5 history API,如果设置为true,所有的跳转将指向index.html |
module.exports = { ?devtool: ‘eval-source-map‘, ?entry: ?__dirname + "/app/main.js", ?output: { ???path: __dirname + "/public", ???filename: "bundle.js" ?}, ?devServer: { ???contentBase: "./public",//本地服务器所加载的页面所在的目录 ???historyApiFallback: true,//不跳转 ???inline: true//实时刷新 ?} }
四 Babel
Babel是一个编译JavaScript的平台,它可以编译代码帮你达到以下目的:
- 让你能使用最新的JavaScript代码(ES6,ES7),而不用管新标准是否被当前使用的浏览器完全支持;
- 让你能使用基于JavaScript进行拓展的语言,如React的JSX;
Babel其实是几个模块化的包,其核心功能位于称为babel-core的npm包中,webpack可以把其不同的包整合在一起使用,对于每一个你需要的功能或拓展,你都需要安装单独的包(用得最多的是解析Es6的babel-env-preset包和解析JSX的babel-preset-react包)。
module.exports = { ???entry: __dirname + "/app/main.js",//已多次提及的唯一入口文件 ???output: { ???????path: __dirname + "/public",//打包后的文件存放的地方 ???????filename: "bundle.js"//打包后输出文件的文件名 ???}, ???devtool: ‘eval-source-map‘, ???devServer: { ???????contentBase: "./public",//本地服务器所加载的页面所在的目录 ???????historyApiFallback: true,//不跳转 ???????inline: true//实时刷新 ???}, ???module: { ???????rules: [ ???????????{ ???????????????test: /(\.jsx|\.js)$/, ???????????????use: { ???????????????????loader: "babel-loader", ???????????????????options: { ???????????????????????presets: [ ???????????????????????????"env", "react" ???????????????????????] ???????????????????} ???????????????}, ???????????????exclude: /node_modules/ ???????????} ???????] ???}};
现在你的webpack的配置已经允许你使用ES6以及JSX的语法了。
五 module
module主要是用来配置加载器(loaders)。webpack本身只能处理javascript模块,如果要处理其他类型的文件,就需要使用loader进行转换,每一种文件会用不同的加载器处理。
loadres,preLoadres,postLoaders的配置主要包括以下几项:
- test:一个匹配loaders所处理的文件的拓展名的正则表达式(必须)
- loader: loader的名称(必须)
- include/exclude: 手动添加必须处理的文件/文件夹,或屏蔽不需要处理的文件/文件夹(可选)
- query: 为loaders提供额外的设置选项(可选)
module: { ???exprContextCritical: false, ???rules: [ ?????{ ???????test: /\.ts$/, ???????enforce: ‘pre‘, ???????loader: ‘tslint-loader‘, ???????exclude: /target/ ?????}, ?????{ ???????test: /\.tsx?$/, ???????use: [ ?????????{ ???????????loader: ‘babel-loader‘, ???????????options: { ?????????????cacheDirectory: ‘./.babelcache/‘, ?????????????plugins: [‘angularjs-annotate‘] ???????????} ?????????} ???????], ???????enforce: ‘post‘, ???????exclude: createBabelExclude() ?????}, ?????{ ???????test: /\.json$/, ???????loader: ‘json-loader‘ ?????}, ?????{ ???????test: /\.html$/, ???????loader: ‘html-loader‘ ?????}, ?????{ ???????test: require.resolve(‘highcharts‘), ???????loader: ‘expose-loader?Highcharts‘ ?????} ???] ?}
六 resolve
resolve用来配置文件路径的指向。可以定义文件跟模块的默认路径及后缀等,节省webpack搜索文件的时间、优化引用模块时的体验。常用的包括alias,extensions,root,moduleDirectories属性。
- alias: 是个对象,把资源路径重定向到另一个路径
- extensions: 是个数组,定义资源的默认后缀,比如定义后引用a.js、b.json、c.css等资源可以不用写后缀名直接写a、b、c
- root: 是个数组,通过绝对路径的方式来定义查找模块的文件夹。可以是一个数组,主要是用来增加模块的搜寻位置使用的。root 的值必须是绝对路径,使用path.resolve设置。
- modulesDirectories: 是个数组,用来设置搜索的目录名的,默认为["web_modules", "node_modules"]
resolve: { ???????//查找module的话从这里开始查找 ???????root: ‘E:/github/flux-example/src‘, //绝对路径 ???????//自动扩展文件后缀名,意味着我们require模块可以省略不写后缀名 ???????extensions: [‘‘, ‘.js‘, ‘.json‘, ‘.scss‘], ???????//模块别名定义,方便后续直接引用别名,无须多写长长的地址 ???????alias: { ???????????AppStore : ‘js/stores/AppStores.js‘,//后续直接 require(‘AppStore‘) 即可 ???????????ActionType : ‘js/actions/ActionType.js‘, ???????????AppAction : ‘js/actions/AppAction.js‘ ???????} ???}
七 plugins
插件是用来拓展webpack的功能的,会在整个构建过程中生效,执行相关的任务。Loadres和Plugins是完全不同的,loaders是在打包构建过程中用来处理源文件的(JSX,Scss,Less),一次处理一个,插件并不是直接操作单个文件,它直接对整个构建过程起作用。webpack有很多内置插件和第三方插件。使用某个插件,先用npm安装,然后在webpack配置的plugins关键字部分添加该插件的一个实例。
比如常用的HtmlWebpackPlugin,这个插件的作用是依据一个简单的index.html模板,生成一个自动引用你打包后的JS文件的新index.html。这在每次生成的js文件名称不同时非常有用(比如添加了hash值)。
安装:
npm install --save-dev html-webpack-plugin
这个插件自动完成了我们之前手动做的一些事情,在正式使用之前需要对一直以来的项目结构做一些更改:
(1)移除public文件夹,利用此插件,index.html文件会自动生成,此外CSS已经通过前面的操作打包到JS中了。
(2)在app目录下,创建一个index.tmpl.html文件模板,这个模板包含title等必须元素,在编译过程中,插件会依据此模板生成最终的html页面,会自动添加所依赖的css,js,favicon等文件.
index.tmpl.html中的模板源代码如下:
<!DOCTYPE html><html lang="en"> ?<head> ???<meta charset="utf-8"> ???<title>Webpack Sample Project</title> ?</head> ?<body> ???<div id=‘root‘> ???</div> ?</body></html>
(3)新webpack的配置文件,方法同上,新建一个build文件夹用来存放最终的输出文件
const webpack = require(‘webpack‘);const HtmlWebpackPlugin = require(‘html-webpack-plugin‘);module.exports = { ???entry: __dirname + "/app/main.js",//已多次提及的唯一入口文件 ???output: { ???????path: __dirname + "/build", ???????filename: "bundle.js" ???}, ???devtool: ‘eval-source-map‘, ???devServer: { ???????contentBase: "./public",//本地服务器所加载的页面所在的目录 ???????historyApiFallback: true,//不跳转 ???????inline: true//实时刷新 ???}, ???module: { ???????rules: [ ???????????{ ???????????????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" ???????????????????} ???????????????] ???????????} ???????] ???}, ???plugins: [ ???????new webpack.BannerPlugin(‘版权所有,翻版必究‘), ???????new HtmlWebpackPlugin({ ???????????template: __dirname + "/app/index.tmpl.html"//new 一个这个插件的实例,并传入相关的参数 ???????}) ???],};
执行npm start,可以发现build文件夹下面生成了bundle.js和index.html
介绍一些常用的插件:
插件 | 作用 |
extract-text-webpack-plugin | 第三方插件,将 CSS 打包成独立文件,而非内联。 |
HotModuleReplacementPlugin | 代码热替换 |
HtmlWebpackPlugin | 生成 HTML 文件,配合 ExtractTextPlugin 可以加入打包后的 js 和 css。 |
NoErrorsPlugin | 报错但不退出 webpack 进程。 |
DefinePlugin | 主要用来定义全局的环境变量,以便我们在自己的程序中引用它。 |
代码热替换
代码热替换在开发的时候无需刷新页面即可看到更新,只在开发环境的配置文件使用,具体配置如下。
npm install --save-dev webpack-dev-server webpack-dev-middleware express
把webpack/hot/dev-server加入到 webpack 配置文件的 entry 项:
<!-- webpack.config.dev.js -->entry: [ ???‘webpack-dev-server/client?http://localhost:3000‘, ???‘./src/app.js‘],
把new webpack.HotModuleReplacementPlugin()加入到 webpack 配置文件的 plugins 项:
<!-- webpack.config.js -->plugins: [new webpack.HotModuleReplacementPlugin()]
在项目根目录新建个server.js文件,将server部分分离到一个单独的 :
<!-- server.js -->var webpack = require(‘webpack‘);var WebpackDevServer = require(‘webpack-dev-server‘);var config = require(‘./webpack.config‘);var compiler = webpack(config);var server = new WebpackDevServer(compiler, {publicPath: config.output.publicPath,hot: true,historyApiFallback: true,stats: {colors: true,hash: false,timings: true,chunks: false,chunkModules: false,modules: false}});server.listen(3000, ‘localhost‘, function(err, result) {if (err) {return console.log(err);}console.log(‘Listening at http://localhost:3000/‘);});
在 package.json 中定义启动监听热加载:
<!-- package.json -->"scripts": { ?"start": "node server.js"}
现在你可以通过运行npm start启动服务器。
webpack
原文地址:https://www.cnblogs.com/lyy-2016/p/8531102.html