Webpack在生产环境中有一个重要的作用就是减少http的请求数,就是把多个文件打包到一个js里,这样请求数就可以减少好多

一、安装

1、先装好node和npm,因为webpack是一个基于node的项目。然后 npm install -g webpack webpack-cli 全局安装webpack webpack-cli

2、新建项目文件夹,比如webpack_demo,然后新建一个package.json的文件在项目根目录下 npm init //询问一些问题:按回车选择默认值 自动生成文件package.json

  • npm install webpack webpack-cli --save-dev

  • npm i webpack webpack-cli--D //这行命令中, i 是 install 的缩写。 --D 是 --save-dev 的缩写。 (--save-dev作用是安装的插件的同时,将插件名写入package.json的devDependencies列表中) 目前是开发环境,所以需要加上-dev,用户运行不需要依赖这个包 如果用户运行需要依赖这个包,那么就不加-dev,直接是--save,保存到生产环境

    需要补充的是,刚才输入的 --save-dev 的含义是: ①将所安装的包分类到开发模式下 ②将安装过的包写入到 package.json 配置文件

    至此,webpack安装完成

3、在项目根目录下,建立

  •   	src源代码文件夹——开发环境
    
  •   	dist生产环境文件夹(里面的文件都是webpack自动生成的)
    
  •   	./当前目录
    
  •   	../父级目录
    
  •   	/根目录
    

项目目录: ./index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <script src="./dist/main.js"></script>
    <!-- src引入的文件将在接下来由 webpack 打包创建 -->
</body>
</html>

./src/index.js:

import {name} from './init';//引入 init.js 存于 name , (js后缀可以省略)
alert(name);

./src/init.js:

var name = "newApp";
export {//ECMAScript 6 语法 , 向外暴露接口供其他文件调用时使用
    name//将变量 name 指定为向外暴露成员
};

4、执行打包(直接打包,没有配置文件的情况下),上面多个文件文件执行打包:webpack

5、在package.json里面配置 可以在在package.json文件的"scripts"属性下增加了"build"属性,即 "build": "webpack --mode production --progress --display-modules --colors --display-reasons" 这样使用npm run build,即可执行webpack打包

"scripts": { "test": "echo "Error: no test specified" && exit 1", "dev": "webpack --mode deveplopment", "build": "webpack --mode production" } 就可以在命令行使用npm run dev执行打包操作了

  • npm run dev (开发环境输出的demo.js没有压缩),是平时我们写代码的形式
  • npm run build (生产模式输出的demo.js压缩过) ★如果是直接进行打包,而没有配置文件,那么使用npm run dev,那么会默认打包src文件夹下的index.js文件,打包完成后是main.js文件(放在dist),你有没有发现我们一开始安装webpack的时候并没有这个文件生成,所以更别提什么index.js文件了,所以这些我们需要手动创建

不管有没有使用index.js,都会打包该文件放到main.js里面,这是没有配置文件的情况下,默认入口文件是index.js,如果没有创建index.js,那么打包就会报错 如果有配置文件,那么就严格按照配置文件配置的入口文件来

我们先创建src文件,还有一个dist文件,存放默认的打包生成的文件,然后在src里再创建index.js文件 这样就可以使用npm run dev进行打包了

6、总结:

  • 打包单个文件,直接是webpack demo.js -o demo.bundle.js --mode development 在终端(命令行)中使用webpack打包,打包哪个文件就写上其名字,后面跟上输出的名字,可以给与路径
  • 如果是打包多个文件,且彼此之间有依赖关系,就使用配置文件来进行打包
  • webpack默认打包src文件夹下的index.js文件,如果没有对应文件和文件夹,就需要手动创建
  • 通过配置文件可以修改打包文件入口和输出文件路径

7、webpack的一些相关命令 如果我们更改我们写的代码的时候,就需要重新进行打包,那就是更改一次又手动进行打包一次,那是很麻烦的,所以我们可以使用如下命令监听这个事件,源文件一更新,就会进行自动打包;一开始watch时关闭地,我需要将它打开:npx webpack --mode development --watch

注意: 这个命令只是单纯监听了默认的打包路径,也就是能监听到src下index.js的变化,也能够随将变化时进行保存刷新后其自动打包,但是,并不能监听到demo.js. 还有就是你的执行这个命令的时候,它必需属于一直监听的状态, 如果被停止了,那监听状态也停止.

二、下面介绍使用配置文件进行打包

1、创建webpack.config.js

举例:
const path = require('path');
module.exports = {
  entry: './src/index.js',  //入口文件的配置项
  output: {  //出口文件的配置项
    path: path.resolve(__dirname, 'dist'),   //dist目录所在的绝对路径
    filename: 'main.js'
  },
  module: {//配置 loader  模块:例如解读CSS,图片如何转换,压缩
    rules: [//相关规则写在这里
      {
        test: /\.css$/,//正则表达式:根据后缀为 .css 的文件来匹配 css 文件
        use: [//匹配搭配 css 文件后,打包时使用以下 loader 来处理文件
          { loader: 'style-loader' },//loader 名称
          {
            loader: 'css-loader',//loader 名称
            options: {
              modules: true
            }
          }
        ]
      }
    ]
  },
  plugins:[],  //插件,用于生产模版和各项功能
  mode: 'development'  //打包模式,默认生产者模式,
  devServer:{} //配置webpack开发服务功能
};

2、在当前目录下(package.json所在文件夹)执行:npx webpack,即可自动执行打包

3、各种参数说明:

  • entry:配置入口文件的地址,可以是单一入口,也可以是多入口。(html文件引入唯一的js 文件)
  • output:配置出口文件的地址,在webpack2.X版本后,支持多出口配置。
  • module:配置模块,主要是解析CSS和图片转换压缩等功能。
  • plugins:配置插件,根据你的需要配置不同功能的插件。
  • devServer:配置开发服务功能,后期我们会详细讲解。
  • [name]的意思是根据入口文件的名称,打包成相同的名称,有几个入口文件,就可以打包出几个文件
  • path :入口文件最终要输出到哪里,
  • filename:输出文件的名称
  • publicPath:公共资源路径
  • webpack:普通打包
  • webpack -p:压缩打包
  • webpack -p -w:监听所有需要打包的代码,只要有代码被改动并保存后,就会自动进行打包

4、如果入口文件有多个,如果output只定义一个出口文件,那么所有的入口文件都会被打包到这一个出口文件;如果想各自生成自己对应的出口文件,那么就得重新配置出口文件,如:

const path = require('path');
module.exports = {
  entry:{
		main:'./src/script/main.js',
		a:'./src/script/a.js'
	},
  output: {  //出口文件的配置项
    path: path.resolve(__dirname, 'dist'),   //dist目录所在的绝对路径
    filename: '[name]-[hash]-[chunkhash].js'  //[name]:名字和入口文件一样 【hash】:随机生成的本次打包的hash值  [chunkhash]:要打包文件的版本号,除非文件修改了,否则都是不变的
  }
};

5、打包过后的文件名是变化的,那么在index.html中引入该文件,难道每次都需要修改路径名称吗,可以使用插件来自动生成:npm install html-webpack-plugin --save-dev

在webpack.config.js中

var htmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path');
module.exports = {
  entry:{
		main:'./src/script/main.js',
		a:'./src/script/a.js'
	},
  output: {  //出口文件的配置项
    path: path.resolve(__dirname, 'dist'),
    filename: 'js/[name]-[hash]-[chunkhash].js' ,
		publicPath:'static'  //当项目需要上线时,加上这个,那么打包后生成的js文件,前面都会加上static,如:<script type="text/javascript" src="static/js/0e8f76480769da375fb2.js"></script></body>
  },
	plugins:[
		new htmlWebpackPlugin({
			template:'index.html',  //以根目录下面的index.html为模板文件进行更新
			filename:'index-[hash].index',  //生成的html文件的名称包含hash值,自定义生成的html文件名,这样每次都会生成一个不同hash的 index文件,不建议这样使用,直接是index.html就好,默认就是index.html,可以不用设置
			inject:'head',  //打包后的js文件放置于头部,即</head>上面
			title:'webpack is good',  //设置html的title,在模板文件使用:<title><%= htmlWebpackPlugin.options.title  %></title>  获取到
			minify:{  //上线前压缩index.html文件
				removeComments:true,  //删除注释
				collapseWhitespace:true  //删除空格
			}
		})
	]
};

这样,就在输出路径dist下,生成了index.html(以根目录下的index为模板),并且也把打包后的js文件引入进去了,全自动,在filename后面加上js/,这样就使得js文件都打包到dist/js目录下,而html文件是直接打包到dist目录下

6、loader,和plugin不同,是专门用来处理资源文件,如转es6,less、图片压缩、图片转base64等的处理

★转es6 首先安装babel:npm install -D babel-loader babel-core babel-preset-env

然后再package.json里面配置: "babel":{ "presets": ["env"] }

在webpack.config.js里面配置

let htmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
	mode: "production",
  entry: './src/index.js',  //入口文件的配置项
  output: {  //出口文件的配置项 ,输出路径为dist目录,即所有文件都要打包到该目录下
    path: path.resolve(__dirname, './dist'),
    filename: 'js/bundle.js',
  },
  module: {//配置 loader  模块:例如解读CSS,图片如何转换,压缩
    rules: [//相关规则写在这里
      {
        test: /\.js$/,//正则表达式:根据后缀为 .css 的文件来匹配 css 文件
        loader:'babel-loader'
      }
    ]
  },
  plugins:[
  	new htmlWebpackPlugin({
  		filename:'index.html',
  		template:'index.html'
  	})
  ],  //插件,用于生产模版和各项功能
  mode: 'development',  //打包模式,默认生产者模式,
  devServer:{} //配置webpack开发服务功能
};

★刚刚webpack打包提示错误: Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema. 解决:需要使用绝对路径。 Error: Cannot find module '@babel/core' 解决:babel-loader的版本不一样,之前的是@7.1.5版本,而现在是@8.0.0版本。所以卸载当前版本,重新安装之前的版本

★打包css文件 首先安装对应的loader,npm install style-loader css-loader --save-dev webpack视所有资源都是一个模块,所有的资源文件都可以打包到webpack中,需要在入口文件import该资源文件 比如:入口文件是index.js,在里面 import './src/style.css' 配置webpack.config.js文件

module: {//配置 loader  模块:例如解读CSS,图片如何转换,压缩
	rules: [//相关规则写在这里
		{
			test: /\.js$/,//正则表达式:根据后缀为 .js 的文件来匹配 js 文件
			loader:'babel-loader'
		},
		{
			test: /\.css$/,//正则表达式:根据后缀为 .css 的文件来匹配 css 文件
			loader:'style-loader!css-loader!less-loader' //css-loader使得在js里面可以处理css文件,style-loader使得js处理完的样式插入到index.html页面中
		}
	]
},

★遇见一系列错误,以安装npm install babel-core@7.0.0-bridge.0 --save-dev结束,成功打包了css文件

★转换less文件 npm install less-loader --save-dev 创建app.less文件,在入口文件引入:import './app.less' 配置webpack.config.js文件

{
	test:/\.less$/,
	loader:'style-loader!css-loader!less-loader' 
}

★打包图片文件 npm install file-loader --save-dev 1、在css文件中引入图片 配置webpack.config.js文件

{
	test:/\.(png|jpg|gif|svg)$/i,
	loader:'file-loader' ,
	query:{
		name:'img/[hash].[ext]'
	}
}

默认是打包到dist目录下,如果要想打包到dist/img下,可以添加query,如上所示。

【注意】要查看loader的用法,可以去https://www.npmjs.com/,搜索对应的loader查看用法 loader:'style-loader!css-loader!less-loader loader的处理方式是从右到左,先处理less-loader,然后依次到左

★url-loader,可以处理图片和文件,当原始文件大小大于指定的值的时候,会交给file-loader处理,小于指定的值的时候,会转为base64位编码,不再是url了,而是一段编码 合理分配图片,是base64嵌入页面,还是通过http求求过来,http请求过来的图片可以缓存,base64编码不行

{
	test:/\.(png|jpg|gif|svg)$/i,
	loader:'url-loader' ,
	query:{
	limit:20000,  //即20k
		name:'img/[hash].[ext]'
	}
}

★img-webpack-loader,配合file-loader、url-loader一起使用,压缩通过http请求的图片大小

{
	test:/\.(png|jpg|gif|svg)$/i,
	loaders:[
		'url-loader?limit=20000&name=img/[hash].[ext]',
		'image-webpack-loader'
	]
	
}

三、热更新 1、在webpack.config.js里面配置devServer devServer:{ contentBase:path.resolve(__dirname,'dist') //基本目录结构,监听哪里的代码 host:'10.1.28.102', //ip地址,不建议填localhost 命令行ipconfig查看ipv4的值即是ip地址 compress:true, //服务器压缩参数,是否启用服务器压缩,一般启用 port:1717 //任何喜欢的数字 } 2、安装服务:npm install webpack-dev-server --save-dev 3、配置package.json "scripts": { "server": "webpack-dev-server", }, 4、运行命令:npm run server 注意:是conteneBase,不是contentPath 运行命令是npm run server,不是webpack-dev-server

四、live-server 本地开发常常需要搭建临时的服务,第一时间我们会想到用http-server。 但现在流行修改文件浏览器自动刷新hot socketing(热拔插),如live-reload。 若想浏览器自动打开项目,用opener。 现在live-server实现了三个插件的所有功能,并且很简单就能启动一个看起来很专业的本地服务

  • 初始化npm:npm init
  • 安装live-server:cnpm install -g live-server
  • 启动live-server:live-server 如果你比较懒,可以在package.json中增加start中增加新的脚本
"scripts": {
  "server": "live-server ./ --port=9090"
}

然后执行 npm run server 浏览器会自动打开,并且当你修改本地文件,浏览器都会立即同步

五、案例之打包css文件

1、模块:CSS文件打包Loaders Loaders是Webpack最重要的功能之一,他也是Webpack如此盛行的原因。通过使用不同的Loader,Webpack可以利用脚本和工具,从而对不同的文件格式进行特定处理。 注意:所有的Loaders都需要在npm中单独进行安装,并在webpack.config.js里进行配置。 Loaders的配置参数:

  • test:用于匹配处理文件的扩展名的表达式,这个选项是必须进行配置的;
  • use:loader名称,就是你要使用模块的名称,这个选项也必须进行配置,否则报错;
  • include/exclude:手动添加必须处理的文件(文件夹)或屏蔽不需要处理的文件(文件夹)(可选);
  • query:为loaders提供额外的设置选项(可选)。

2、打包css文件, 首先在src文件夹下,建立一个css文件夹,在文件夹下需要打包的css文件 css文件建立好后,需要引入到入口文件中,才可以打包到,这里我们引入到entry.js中。

style-loader:用来处理css文件中的url()等 安装:npm install style-loader --save-dev

css-loader:用来将css插入到页面的style标签 安装:npm install css-loader --save-dev

两个loader都下载安装好后,我们就可以配置我们loaders了。 修改webpack.config.js中module属性中的配置代码如下(三种写法):

第一种写法:直接用use。
module:{
	rules:[
		test:'/\.css$/',
		use:['style-loader','css-loader']
	]
}
第二种写法:把use换成loader。
module:{
	rules:[
		test:'/\.css$/',
		loader:['style-loader','css-loader']
	]
}
第三种写法:用use+loader的写法:
module:{
	rules:[
		{
			test:/\.css$/,
			use:[
				{
					loader:'style-loader'
				},
				{
					loader:'css-loader'
				}
			]
		}
	]
}

9、插件配置:配置JS压缩 上线前,压缩js代码,通过使用插件的方式来实现 引入一个uglifyjs-webpack-plugin(JS压缩插件,简称uglify)。 注意:虽然uglifyjs是插件,但是webpack版本里默认已经集成,不需要再次安装,但是是需要引入的

在webpack.config.js里面引入 const uglify = require('uglifyjs-webpack-plugin'); 引入后,在plugins配置里new一个uglify对象即可使用, plugins:[ //注意是[],不是{} new uglify() //后面不加分号,多个的话加逗号 ] 最后,在终端命令行,使用webpack进行打包,压缩js文件 npm run server用在开发环境,启动服务器,是对代码进行预览的,此时的代码不需要压缩,否则无法调试 所以上面的开发完毕之后,使用下面的进行打包压缩,然后直接上线,不需要再进行热更新在调试什么的了 webpack是打包压缩,用于生产环境,打包压缩之后就上线了

webpack打包的时候发生错误:Error: Cannot find module 'uglifyjs-webpack-plugin' 执行即可npm install --save-dev html-webpack-plugin

在实际开发中,webpack配置文件是分开的,开发环境一个文件,生产环境一个文件

10、插件配置:HTML文件的发布

此时,将dist里面的index.html剪切到src目录下面,并去掉我们的JS引入代码(webpack会自动为我们引入JS), <script src="./bundle.js" type="text/javascript" charset="utf-8"></script> 因为这才是我们真实工作的目录文件结构。

然后配置webpack.config.js文件 引入html-webpack-plugin插件 const htmlPlugin = require('html-webpack-plugin');

再进行安装该插件 npm install --save-dev html-webpack-plugin

在webpack.config.js文件,添加参数

plugins:[
	new htmlPlugin({
		minify:{
			removeAttributeQuotes:true
		},
		hash:true,
		template:'.src/index.html'
	})
]

说明:

  • minify:是对html文件进行压缩,removeAttrubuteQuotes是却掉属性的双引号。如<div id="title"></div>里的双引号
  • hash:为了开发中js有缓存效果,所以加入hash,这样可以有效避免缓存JS。
  • template:是要打包的html模版路径和文件名称。

此时,完全不需要创建dist目录,dist目录下也不需要创建任何文件,全部webpack自动 index.html文件已经被打包到我们的dist目录下了,并且自动为我们引入了路口的JS文件。

执行完webpack之后,文件已经被打包压缩了,然后执行npm run server,即可在本地查看效果

11、图片迈坑:CSS中的图片处理

第一在src目录下新建一个images文件夹,把图片放入images文件夹

第二然后安装loader:file-loader url-loader npm install --save-dev file-loader url-loader

  • file-loader:解决引用路径的问题,拿background样式用url引入背景图来说,我们都知道,webpack最终会将各个模块打包成一个文件,因此我们样式中的url路径是相对入口html页面的,而不是相对于原始css文件所在的路径的。这就会导致图片引入失败。这个问题是用file-loader解决的,file-loader可以解析项目中的url引入(不仅限于css),根据我们的配置,将图片拷贝到相应的路径,再根据我们的配置,修改打包后文件引用路径,使之指向正确的文件。

  • url-loader:如果图片较多,会发很多http请求,会降低页面性能。这个问题可以通过url-loader解决。url-loader会将引入的图片编码,生成dataURl。相当于把图片数据翻译成一串字符。再把这串字符打包到文件中,最终只需要引入这个文件就能访问图片了。当然,如果图片较大,编码会消耗性能。因此url-loader提供了一个limit参数,小于limit字节的文件会被转为DataURl,大于limit的还会使用file-loader进行copy。

第三使用loader,记得在loader使用时不需要用require引入,使用plugins才需要使用require引入。

module:{
	rules:[
		{
			test:/\.(png|jpg|gif)/,
			use:[{
				loader:'url-loader',
				options:{
					limit:5000
				}
			}]
		}
	]

}

之所以只引入url-loader,是因为url-loader已经包含了file-loader的功能

  • test:/.(png|jpg|gif)/是匹配图片文件后缀名称。
  • use:是指定使用的loader和loader的配置参数。
  • limit:是把小于500000B的文件打成Base64的格式,写入JS。

12、图片迈坑:CSS分离与图片路径处理

12.1、把CSS从JavasScript代码中分离出来

第一安装extract-text-webpack-plugin插件 npm install --save-dev extract-text-webpack-plugin

第二在配置文件里引入 const extractTextPlugin = require(''extract-text-webpack-plugin);

第三在plugins配置文件里new一下 plugins:[ new extractTextPlugin('css/style.css'); //这里的css/style.css是分离后的路径位置,位于dist目录下 ]

第四修改原来我们的style-loader和css-loader。

module:{
	rules:[
		{
			test:/\.css$/,
			use:extractTextPlugin.extract({
				fallback:'style-loader',
				use:'css-loader'
			})
		}
	]
}

利用extract-text-webpack-plugin插件很轻松的就把CSS文件分离了出来,但是CSS路径并不正确 12.2图片路径问题 第一在webpack.config.js 上方声明一个对象,叫website。

var website ={
    publicPath:"http://10.1.28.102:1717/"
}

第二在output选项中引用这个对象的publicPath属性。 //出口文件的配置项

output:{
     //输出的路径,用了Node语法
     path:path.resolve(__dirname,'dist'),
     //输出的文件名称
     filename:'[name].js',
     publicPath:website.publicPath
 }

第三使用webpack进行打包

如何把图片放到指定的文件夹下,如images下面 修改modules里面的图片url-loader选项

modules:{
	rules:[
		test:'\/.(png|jpg|gif)\',
		options:{
			limit:5000,
			outputPath:'/images/'
		}
	]
}

13、图片迈坑:处理HTML中的图片

第一安装 html-withimg-loader
npm install --save-dev html-withimg-loader

第二配置webpack.config.js
{
	test:'/\.(htm|html)$/i',  //注意(htm|html)加括号
	use:['html-withimg-loader']
}

14、给webpack增加babel支持 安装相关依赖包 npm c install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react 在webpack.config.js里面进行配置

{
    test:/\.(jsx|js)$/,
    use:{
        loader:'babel-loader',
        options:{
            presets:[
                "es2015","react"
            ]
        }
    },
    exclude:/node_modules/
}

但是不建议直接在webpack.config.js中进行配置,而是把配置写在.babelrc文件里 在项目根目录新建.babelrc文件,并把配置options写到文件里。

.babelrc  //json格式  presets-渲染器
{
    "presets":["react","**es2015**"]
}
.webpack.config.js里的loader配置
{
    test:/\.(jsx|js)$/,
    use:{
        loader:'babel-loader',
    },
    exclude:/node_modules/  //不转node_modules里面的es6语法
}

ENV: 现在网络上已经不流行babel-preset-es2015,现在官方推荐使用的是babel-preset-env,那我们紧跟潮流 安装最新的env npm n install --save-dev babel-preset-env 然后修改.babelrc里的配置文件。其实只要把之前的es2015换成env就可以了。 { "presets":["react","env"] }

15、打包后如何调试 调试只针对于开发环境 上线前,一定要删除devtool: 'eval-source-map',然后再进行打包,否则有安全隐患 个人意见是,如果大型项目可以使用source-map,如果是中小型项目使用eval-source-map就完全可以应对,需要强调说明的是,source map只适用于开发阶段,上线前记得修改这些调试设置。

module.exports = {
  devtool: 'eval-source-map',
  entry:  __dirname + "/app/main.js",
  output: {
    path: __dirname + "/public",
    filename: "bundle.js"
  }
}

16、实战技巧:开发和生产并行设置

依赖dependencies

开发环境
开发依赖devDependencies

生产环境 (上线环境) 生产依赖dependencies

npm install jquery //安装到全局环境,本项目下面是没有的,如果别人拷走了,那么拷走的文件里面是不包含jquery,可能会报错

npm install jquery --save,安装到本项目下面,并且写入dependencies

拿到别人的项目,比如从github上下载下来了一个新项目,首先需要npm install进行初始化安装 会搜索package.json,搜索里面的包进行安装。如果全局里面有相关的包,那么直接就从本机全局里面拷贝,不用下载

拿到别人的项目,比如从github上下载下来了一个新项目,首先需要npm install进行初始化安装,如果只安装生产环境的包,那么就是npm install --production,而不是npm install

☆☆☆☆配置生产和开发环境并行

webpack.config.js是存在于node环境中,都是用node命令运行

局部安装webpack npm install --save-dev-webpack,webpack被安装到了项目文件夹node_modules文件夹下面