一、webpack和npm的关系
- npm是包管理器,及可以执行命令包(webpack可以看成是功能强大的命令包,除了webpack还有其它如webpack-dev-server);
- webpack可以看成是功能强大的命令包:它还可以执行其它的功能包(装载机,插件)
二、全局安装/项目安装?[1]
重点就在
这个包是否要作为CMD命令来使用
及本地项目是否都差不多,因此放在全局
- 这个包要作为CMD命令使用:要全局安装 。如yarn cnpm webpack-dev-server等
即安装到node_global,因为node_global在系统环境中配置了路径,
故而里面的脚本能在cmd中直接运行
此时这个命令的运行环境是全局环境:对应全局的webpack版本
- 不作为CMD命令使用:项目安装
在package.json的scripts中
也可以执行命令包,此时通过npm run 命令别名
来执行
因为Npm会临时把本地项目命令加载到系统环境path中,故而命令包放在本地也能通过npm run来执行
√
如果本地有安装,则执行本地的。否则执行的是全局的命令包。对应的执行环境webpack也是一样的。
三、打包前的准备工作(操作的webpack为3.8.1)
- 创建项目:
$ npm init
- 全局安装webpack:
$ npm install webpack -g
及脚手架$ npm install webpack-cli -g
全局安装是为了CMD使用
webpack 命令
- 本地安装webpack:
$ npm install webpack --save-dev
四、js的打包
方式①:
$ webpack 源文件 目标文件
即:把源文件js打包到目标文件
如:$ webpack ./src/app.js ./dist/main.js
其它参数:
--watch
开启热跟新-p
压缩目标文件-d
调试时,方便定位源文件问题:
- 命令行太长,写法比较复杂
- 直接采用的是webpack命令,此时,运行环境为 全局的webpack包,并非项目的webpack版本,可能会产生和项目的一些冲突
方式②:
通过配置文件,来简化webpack命令
创建配置文件 webpack.config.js module.exports={ entry:'./src/app.js', output:{ path: __dirname + '/dist', //__dirname 是Node的变量,表示根目录。注意:path只能是绝对路径 filename: 'main.[hash:5].js' //[hash:5]表示取hash的5位,这边是为了更新浏览器本地缓存 } //json文件不能注释,这边是为了解释说明用的
因为webpack会自动会查找webpack.config.js,且这边已经配置好了源文件及目标文件
此时可以:$ webpack
即可打包。或$ webpack --watch
等问题:
- 命令行还是不够简洁,一些参数还是没办法配置
- (同上)直接采用的是webpack命令,此时,运行环境为 全局的webpack包,并非项目的webpack版本
方式③:
通过package.json的scripts来运行脚本
修改package.json的scripts: "scripts": { "build": "webpack --watch -d", "prod": "webpack -p" }
此时,可以直接
$ npm run build
或$ npm run prod
来运行脚本优点:
命令全都由npm来运行,且命令简洁明了(便于知道有哪些命令)
npm来运行,所以采用的是项目的脚本(包括其它的脚本也是一样)
五、结合html
前面已经学会js的打包,但毕竟运行在浏览器的入口是html,那怎么和html结合呢?
方式①:
创建html,手动引入打包后的js
。问题:
- 打包后的style,script标签要手动写入html。麻烦
- 以及hash问题,每次生成的打包文件名还不一样,又要重新写入html。麻烦
方式②:使用
html-webpack-plugin
插件作用:
- 程序还是正常从entey入口开始打包
然后
,对html模板,引入<script src="打包后的js">
,及其它操作(压缩,hash等等)安装插件 $ npm install html-webpack-plugin --save-dev
使用插件(在webpack.config.js中引入及挂载) 引入: const HtmlWebpackPlugin = require('html-webpack-plugin'); 挂载: module.exports={ plugins: [ new HtmlWebpackPlugin({ template:"./src/index.html", //html的模版文件 filename: 'one.html', //生成目标html的名字 minify: {collapseWhitespace:true} ,//压缩html及配置压缩类型 hash:true//会在所有注入的静态资源添加webpack每次编译产生的唯一hash值 }) ] } //hash:true的效果 <script type="text/javascript" src="main.dce13.js?dce1306176497ad4a85d"></script></body> 可以发现dce13:为main.[hash:5]生成的hash值 ?dce1306176497ad4a85d为这次生成的hash值,所有静态文件都添加了这个
html-webpack-plugin详细配置点击查看
minify的详细配置点击查看
高级篇----多html的配置
- 从实际意义出发,肯定需要配置多入口
之前entry是string类型,这次我们采用array类型 entry: { "entry1":'./src/app.js', //其中,"entry1"作为chunk代码块 "entry2":'./src/app1.js', "entry3":'./src/app2.js', },
使用插件 plugins: [ //tips: plugins执行顺序也是从后到前执行。即先执行底下的插件,再上面的插件 new HtmlWebpackPlugin({ template:"./src/index_other.html", filename: 'two.html', //这个是第二个html的出口 minify: {collapseWhitespace:true} , hash:true, chunks:['entry2','entry3'] //这边测试处理两个,也可以通过excludeChunk:['entry1'] 取余 }), new HtmlWebpackPlugin({ template:"./src/index.html", filename: 'one.html', minify: {collapseWhitespace:true} , hash:true, chunks:['entry1'] //这个配置是要处理的chunk代码块,默认为all即所有入口的都处理 }) ] -------------------------------------------------------- 说明: chunks:[] //数组内的值为entry配置里面的key值。这边即'entry1','entry2','entry3' excludeChunk:[]//这个配置是除了数组内的chunk代码块会去处理。即取反
这边还有个问题:多个html-webpack-plugin插件处理入口,于是会生成多个目标js。 之前: output:{ path: __dirname + '/dist', filename: 'main.[hash:5].js' //多html-webpack-plugin插件时,会生成多个同名的该文件,会同名覆盖 } 改为=> output:{ path: __dirname + '/dist', filename: '[name].[hash:5].js' //name为对应entry的chunk名,同上 } 说明:[name]表示为对应entry的chunk名,同上
总结:对比一个html,区别在于:
需要多个入口,然后使用多个html-webpack-plugin插件处理入口对应的chunk,然后生成多html
六、结合css
前面学习了js的打包,以及把打包后的Js结合html,结合html我们采用插件来自动化帮我们处理一些事情。
但是怎么结合css呢,css不是浏览器入口,只能通过源js引入该css。再处理
但是webpack默认只认得js,因此要采用装载机来处理css,再放到html中。
方式①:使用
'style-loader', 'css-loader'
。这种是<style>样式
的方式原理:
- 在js中引入该css。import css from './one.css';
- 然后,
css-loader,实现从对应css文件导入文件到js中
- 然后,
style-loader,实现从js中,提取出css
,然后在html中,写入<style>中
安装装载机 $ npm install css-loader style-loader --save-dev
使用装载机(在webpack.config.js中挂载) 相比插件不用引进 module: { rules: [ { test: /\.css$/, //正则表达式,匹配对应的后缀文件,然后用底下对应的装载机处理 use: [ 'style-loader', 'css-loader' ] //装载顺序为***从右到左*** } ] }
说明:
css-loader:
即:编译。加载.css文件,注入到js文件中,以字符串的形式存在style-loader:
即:提取。使用<style>将css-loader内部样式注入到我们的HTML页面- css-loader/style-loader详细配置点击查看
这种方式在html生成的是<style>标签
方式②:结合
extract-text-webpack-plugin
插件:实现css分离成文件。这种是<link>样式
的方式安装插件 $ npm install extract-text-webpack-plugin --save-dev
使用插件 引入: const ExtractTextPlugin = require('extract-text-webpack-plugin'); //这边对比css-loader/style-loader的区别 module: { rules: [ { test: /\.css$/, use:ExtractTextPlugin.extract({ fallback: 'style-loader', //提取要用到的装载机 use: [ 'css-loader' ] //编译要用到的装载机 }) } ] } 以及配置plugins: plugins{ new ExtractTextPlugin('style.css') //生成目标css的文件名为style.css }
说明:
- 通过
extract-text-webpack-plugin
插件实现了css的分离,而不是注入js中- extract-text-webpack-plugin详细配置点击查看
- 和webpack4.0+ 不兼容
这种方式在html生成的是<link>标签
- 所以和第一种方式的优劣势对比即为:
<style>和<link>样式的优劣势对比
及css有独立hash等
这边补充对于scss的css文件的处理
安装scss装载机: $ npm install sass-loader node-sass --save-dev
方式一下使用sass-loader装载机: module: { rules: [ { test: /\.scss$/, //这边匹配文件后缀为.scss use: [ 'style-loader', 'css-loader' ,"sass-loader"] //只是这边后面增加该装载机 } ] } ------------------------------------------------------------------ 方式二下使用sass-loader装载机: module: { rules: [ { test: /\.scss$/, use:ExtractTextPlugin.extract({ fallback: 'style-loader', use: [ 'css-loader',"sass-loader" ] }) } ] } 以及配置plugins: plugins{ new ExtractTextPlugin('style.css') }
其它补充
添加hash:
plugins: [new ExtractTextPlugin('style.[hash:5].css')]
七、webpack-dev-server插件的使用
前面有介绍CMD命令包对于全局安装或本地安装的选择,点击回顾
方式①:全局安装$ npm install webpack-dev-server -g
此时,在CMD即可使用该命令:$ webpack-dev-server
//注意此时运行环境为全局的Webpack版本
方式②:项目安装
$ npm install webpack-dev-server --save-dev
此时可以通过配置scripts可以让npm来运行脚本"scripts": { "dev": "webpack-dev-server" }
此时,可以直接
npm run dev
来开启本地服务
补充
webpack.config.js中配置 devServer: { port: 9000, //这边配置端口号 open:true //这边会自动打开浏览器 },
说明
- 配置webpack-dev-server 运行时报错配置 Can't resolve 'webpack/hot/dev-server' 。
说明项目中,没有安装webpack
- webpack-dev-server生成的包并没有放在你的真实目录中,而是放在了内存中
- 和webpack4.0+不兼容,
这边webpack@3.8.1安装2.9.1
- webpack-dev-server的详细配置点击查看
- 对比
webpack --watch
避免了打包文件及实现了热更新
八、
九、区分生产环境和开发环境
- 配置部分区分
- 方式①:在webpack.json的scripts运行脚本时,增加变量并赋值
eg:
"prod": " SET NODE_ENV=production & SET hcl=huchunlin && webpack -p",
配置部分使用:console.log(process.env.NODE_ENV);console.log(process.env.hcl);
说明:process.env.变量
来访问
window系统需要SET 。max系统不需要
- 方式②:不同命令进入,即会执行不同的配置文件
eg:
"prod": " webpack -p --config ./config/prod.js",
即通过--config
来执行指定配置文件
- 方式③:相结合
- 源代码(打包后的文件)区分
通过webpack.DefinePlugin来定义源代码的全局变量。在编译时会进行替换
webpack.config.js中=>定义全局变量 ----------------------------------------------------------------- plugins: [ new webpack.DefinePlugin({ "hcl": JSON.stringify('这个是在webpack.config定义的变量') }) ]
源代码中,比如在app.js中=>使用全局变量 ----------------------------------------------------------------- console.log(hcl)
- 配置文件和源代码都要能区分:结合①和②
-
二、全局安装/项目安装 ↩