webpack实践总结
一、Loader写法及执行顺序
从webpack2起,loader的格式如下:
module: {
rules: [
{test: /\.css$/, use: ['style-loader','css-loader']},
]
}
webpack1中的写法如下:
module: {
loaders: [
{
test: /\.css$/,
loader: 'style-loaer!css-loader'
}
]
}
不管采用哪种写法,需要记住的是loader的执行顺序是从右往左
二、根据模板生成html文件并自动插入脚本和样式的地址
使用html-webpack-plugin插件可达到这一目的,并且插入的文件地址会随着output.publicPath的变更而变更。html-webpack-plugin插件与chunk概念紧密相联
所谓的chunk无非就是代码段,假设入口为index.js,在index.js中导入了a.js和b.js,那么打包出来就会形成一个name为index的chunk,chunk的内容是这三个文件合起来的内容
该插件不是webpack自带的,需要先安装到开发环境( npm html-webpack-plugin --save-dev),然后在webpack配置文件中有几个关键的配置项:
module.exports = {
plugins:[
new htmlPlugin({
filename: '最终输出的html文件地址',
template: '模板文件地址',
hash:false,
chunks: ['index','common']
})
]
}
hash:为true时在html中插入的文件地址格式会变为xxx.js?a3c9073cfd20130af5e3,生成hash的主要作用是用来处理浏览器缓存
chunks:可选属性,要插入哪些chunk生成的文件,如果未指定,则把所有的chunk形成的文件都插入。
在多页面中通常每个页面都有一个js做为入口文件,index.html使用index.js,user.html使用user.js,这里有两个入口,打包出来会形成两个chunk,分别为index和user
entry:{
index:rootPath+'/src/js/index.js',
user:rootPath+'/src/js/user.js'
},
output: {
filename: 'js/[name].js',
path: rootPath+'/dist/'
},
生成index.html时,我们显然不希望把user.js也引用进去,所以这时就必须要指定使用哪些chunk
如果要生成多个html,则需要在plugins数组中创建多个htmlPlugin实例
使用ExtractTextPlugin插件提取的css文件会自动添加到html中
指定了chunk时,如果使用CommonsChunkPlugin提取了公共代码,如果未在配置项中添加该chunk的名字,则生成的html不会插入公共代码文件
假设在html模板中已经手工插入了一些css和js文件,生成的文件会插入到这些文件之后
三、未打包的样式和脚本也想自动插入到html中
在上面例子中我们把打包生成的文件自动插入到了html中,那么不参与打包的文件该怎么处理呢?如果我们采用手动插入方式,那么如果在开发环境时不使用cdn,在生产环境要使用cdn时,不是得手工去改html中的链接吗。
new htmlIncludeAssetsPlugin({
assets: ['js/lib/jq.js'],
append: false, //false,添加到html-webpack-plugin生成的链接之前,true为之后
hash:true, //是否在生成的文件地址后加hash,默认为false
publicPath:'' //自定义publicPath,如果省略或为空则使用output项中指定的publicPath
})
该插件的实例会对所有的html-webpack-plugin实例起作用,也就是在所有生成的html中都插入相应的代码,如果只想在指定的html中追加,可以指定一个file属性
四、项目使用jquery及插件的最佳实践
不管是我们以往的多页面还是vue、react这种mvvm框架中,都建议直接按如下方式使用:
1.在html中直接引入jquery及相应的插件,这样子在代码中就可以正常使用jquery以及相应的插件了
2.如果需要在代码中使用es6的模块导出功能import $ from 'jquery'或者cmd方式加载var $ = require('jquery'),那么你需要把$变量暴露给webpack,按如下方式进行配置
externals: {
jquery: 'window.$'
}
externals的使用场景如下:当我们想引用一个库,然后想在代码中使用cmd或es6的模块引入,加但是又不想让webpack打包,这时就可以使用该配置项。
此步骤不是必须的,不使用es6 import或cmd require并不影响使用jquery及插件
3.如果是自己编写的插件,可以使用es6的import './jqPlugin/globalJq.js'方式导入,此方式会把globalJq.js的代码打包进项目的js中
4.会把jquery打包到项目js中的几种方式
- 使用expose-loader
step1:安装到生产环境:npm install jQuery expose-loader --save
step2:在配置文件中添加一个loader{
test: require.resolve('jquery'),
loader: 'expose?jQuery!expose?$'
}step3,在需要使用jquery的文件中导入模块即可
import $ from 'expose?$!jquery'
import 'jquery-ui' //插件可用此种方式在使用layer.js这个弹层库时会出错
- 使用ProvidePlugin
该插件是webpack自带的,不需要单独安装
step1:npm install jQuery --save
step2:在webpack配置文件的插件选项中添加一个webpack.ProvidPlugin实例(注:webpack是在文件头声明的,const webpack=require('webpack')) - new webpack.ProvidePlugin({$: "jquery",jQuery: "jquery"}),
step3:接下来就是直接使用$了,不需要再导入模块
import 'jquery-ui' //引入jquery-ui插件
$('#app').text()该插件的作用是自动加载模块。 当 使用未赋值的变量时, module 就会自动被加载,并且 identifier 会被这个 module 输出的内容所赋值。上面的变量是$,对应的module是我们安装的jquery模块。
缺点是没有全局上下文,$变量没有声明就可以使用,当使用eslint时无法验证语法错误
5. 为什么推荐直接在html中引入jquery及相应的插件?
采用上面第4条中的做法,在打包时会出现一系列的问题,具体表现在:
1.如果多个文件都使用了jquery,那么打包时,每个文件中都会插入jquery库的代码,代码重复,然后你会想到第2条的抽取公共代码方法
2.使用CommonsChunkPlugin插件把多份代码中都使用到的代码提取为独立文件,这种做法在每次打包时都会计算哪些是公共代码,项目大时找包速度很慢。
3.为了解决打包性能,得改用DllPlugin和DllReferencePlugin插件,打包速度解决了,但是还是得手动把xxx.dll.js插入到html中。(看不明白不要紧,后续会讲到该插件)
看到了吗,使用第4条中的方法绕来绕去最终还是得在html中插入提取到的公共代码或xxx.dll.js,做了一系列的工作,实际上等于脱了裤子放屁
五、css相关处理
在webpack中所有的东西都是模块,css也不例外,只有将css视为模块,才能在webpack中进行打包和压缩,才能自动插入到相应的html中,才能将css转成js对象方式来使用(vue中有该技术)。
1.css-loader和style-loader
css-loader 主要的作用是把css当作模块使用,然后就可以在js中使用 import 'xxx.css'导入样式表,然后参与打包
style-loader 主要的作用是把js中导入的css模块插入到html中形成一个<style>xxxx</style>
step1:安装模块
npm install style-loader css-loader --save-dev
step2:webpack中编写loader
module: {
rules: [
{
test: /\.css$/,
use: [
{ loader: 'style-loader'},
{loader: 'css-loader',options: { modules: true}}
]
}
]
}
2.使用post-loader+autoprefixer自动为css加前缀
某些css属性,要为不同的浏览器加不同的前缀,手动添加相应的前缀是个苦差事,post-loader可以很好的解决这个问题,我们只需写一个正常的样式
div
{
transform:rotate(7deg);
}
使用post-loader后会自动转成
div
{
transform:rotate(7deg);
-ms-transform:rotate(7deg); /* IE 9 */
-moz-transform:rotate(7deg); /* Firefox */
-webkit-transform:rotate(7deg); /* Safari 和 Chrome */
-o-transform:rotate(7deg); /* Opera */
}
网上很多文章比较坑,会告诉你用autoprefixer插件或用post-loader插件,实际上两个插件都需要安装!
npm install autoprefixer post-loader --save-dev
3.使用less-loader来编译.less文件
4.使用extract-text-webpack-plugin插件来提取style-loader向页面中插入的样式
使用前需要先安装该插件,然后使用const ExtractTextPlugin = require("extract-text-webpack-plugin");//导入模块,最后在plugins数组中创建一个实例
new ExtractTextPlugin('css/[name].css'),
使用name属性时,从入口中index.js中抽取出来后的文件是index.css,当然也可以指定为一个固定的名字比如page,css
当我们指定css/xxx.css时,最终的生成路径实际上是webpack的output.path+'css/xxx.css'
5.相关的配置
注意use中的loader顺序,不要写反了
{
// 用正则去匹配要用该 loader 转换的 CSS 文件
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader", // 编译后用什么loader来提取css文件
use: ['css-loader?minimize=true','postcss-loader']
})
},
6.css压缩处理
需要使用optimize-css-assets-webpack-plugin插件来专门处理css。
注意:对于webpack v3或更低版本,请使用optimize-css-assets-webpack-plugin@3.2.0。 optimize-css-assets-webpack-plugin@4.0.0及以上版本支持webpack v4。
如果你搜网上那些教程,一般会告诉你css-loader有压缩属性,又或者告诉你你在pageage.json中创建一个打包的scrpits命令,配置如下:
"scripts": {
"build": "webpack -p",
},
假如你按他们的方法来打包,最后你发现你的css文件中的代码还是原封不动的,根本就没有删除空格,也没有删除注释!
new OptimizeCssAssetsPlugin({
cssProcessor: require('cssnano'),
canPrint: true
})
六、图片资源的处理
主要使用url-loader和file-loader,网上看博文说url-loader是file-loader的升级版,可以独立使用,但是我在webpack2中使用时报错了,安装url-loader后还是得安装file-loader.
容易出错的地方,请查看这篇
七、实时编译并查看运行结果(HRM)
主要使用webpack-dev-server,安装好该包后,需在package.json中和webpack.config.js中进行配置。
首先在package.json的scripts节点增加一个命令,我习惯叫dev,然后在命令行中就可以使用 npm run dev来启动调试服务器了
"scripts": {
"dev": "webpack-dev-server --open --inline --hot
},
open--参数表示启动服务器后自动打开网页
inline 和hot配合实现热刷新,hot参数必须写在这里,在webpack.config中配置无效
接下来在webpack.config中增加一个devServer配置项:
devServer: {
contentBase:'dist', //网站文件目录,一般指向打包输出目录
historyApiFallback: true,//不跳转
progress: true
},
更详细的配置,点我
八、如何处理sourcemap?
主要使用devTool选项,最常用的有以下几种:

上述选项由上到下打包速度越来越快,不过同时也具有越来越多的负面作用,较快的打包速度的后果就是对打包后的文件的的执行有一定影响。
生成source map的目的是为了方便调式,出错时能定位到最原始的资源,不管该资源是react的jsx,还是vue的单文件,因此使用eval选项并没有意义,这也是在上表中没有列出的原因
那为什么也不使用inline-source-map选项呢?主要还是因为打包速度慢,文件体积变大
总结:
在开发环境中我们使用:cheap-module-eval-source-map
在生产环境中我们使用:cheap-module-source-map。
九、区分开发环境和生产环境
const common = require('./webpack.common.js');
const merge = require('webpack-merge');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const webpack=require('webpack')
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const path=require('path')
const rootPath=path.resolve(__dirname,'../')
//const DllReferencePlugin = require('webpack/lib/DllReferencePlugin');
const prodConfig={
plugins:[
new webpack.DefinePlugin({
'process.env': JSON.stringify({env:'development','BASE_API':'http://www.baidu.gov.cn'})
}),
new CleanWebpackPlugin(['build'], {
root: '', // An absolute path for the root of webpack.config.js
verbose: true,// Write logs to console.
dry: false // Do not delete anything, good for testing.
}),
/*
new DllReferencePlugin({
manifest: require('../dist/vendor.manifest.json'),
}),
*/
new UglifyJSPlugin(),
new OptimizeCssAssetsPlugin({
cssProcessor: require('cssnano'),
canPrint: true
})
]
}
module.exports=merge(common,prodConfig)
需要注意的是DefinePlugin中某个项的值的写法,假如你想在代码中访问process.env里存储的内容,那么在定义时必须使用Json.stringify('prod'),或者是'"prod"',而不是'production'
"scripts": {
"build": "webpack --config webpack.prod.js",
"dev": "webpack-dev-server webpack.dev.js",
},
需要注意配置文件的路径,如果不是在根目录下,而是在config文件夹下,则应修改为
webpack实践总结的更多相关文章
- webpack实践(一)- 先入个门
一.前言 webpack是个啥呢?看官网的这段描述. webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler) 在我以前做纯html.css. ...
- webpack实践(三)- html-webpack-plugin
webpack系列博客中代码均在github上:https://github.com/JEmbrace/webpack-practice <webpack实践(一)- 先入个门> < ...
- webpack实践(二)- webpack配置文件
webpack系列博客中代码均在github上:https://github.com/JEmbrace/webpack-practice <webpack实践(一)- 先入个门> < ...
- webpack实践(四)- html-webpack-plugin
webpack系列博客中代码均在github上:https://github.com/JEmbrace/webpack-practice <webpack实践(一)- 先入个门> < ...
- vue+webpack实践
最近使用了vue来做SPA应用,记一波学习笔记. 使用vue+webpack实现前端模块化. vuejs——轻量.学习成本低.双向绑定.无dom的操作.组件的形式编写 推荐官方文档 vue.js官方文 ...
- npm scripts + webpack 实践经验(React、Nodejs)
最近用Webpack+npm scripts+Mongodb+Nodejs+React写了个后台项目,在用Webpack构建过程中遇到了许多坑,就写出来分享一下. 构建工具五花八门,想当年刚学会Gru ...
- webpack实践笔记
1)cross-env 能跨平台地设置及使用环境变量 大多数情况下,在windows平台下使用类似于: NODE_ENV=production的命令行指令会卡住,windows平台与POSIX在使用命 ...
- webpack实践——DLLPlugin 和 DLLReferencePlugin的使用
DLLPlugin 和 DLLReferencePlugin的使用 DLLPlugin 和 DLLReferencePlugin 用某种方法实现了拆分 bundles,同时还大大提升了构建的速度. 1 ...
- 【xinsir】webpack实践
webpack现在是前端必会的技能了,也是在工作中必定用到的.所以,如果我们现在还不会webpack,那么在将来面试中肯定会被扣分的. webpack中文官网:https://www.webpackj ...
随机推荐
- 【洛谷P3225】[HNOI2012]矿场搭建
矿场搭建 题目链接 根据题意,发生事故时会有一个挖煤点坍塌, 只有当这个点是割点,会对图的连通性产生影响, 我们首先Tarjan一遍找到所有割点,将原图除去这些割点后, 遍历一遍,找出所有连通块,分三 ...
- OS_EVENT 信号量
1. OS_EVENT *T2sem=(OS_EVENT *)0; 这句代码的意思是 把OS_EVENT类型的一个指针T2sem赋值为0: 其中 OS_EVENT是数据类型,*代表是指针类型,(O ...
- js 防抖 节流 JavaScript
实际工作中,通过监听某些事件,如scroll事件检测滚动位置,根据滚动位置显示返回顶部按钮:如resize事件,对某些自适应页面调整DOM的渲染:如keyup事件,监听文字输入并调用接口进行模糊匹配等 ...
- 嵌入式:UCOSIII的使用(17.01.24补充)
0.一些移植.系统相关 OS_CFG_APP.H /* --------------------- MISCELLANEOUS ------------------ */ #define OS_CFG ...
- Lucene的原理和应用
随着互联网的迅速普及与发展,网络舆论对社会生活的影响力越来越大, 网络口碑研究也逐渐形成一个新兴行业.有效的网络口碑研究,需要全方位地倾听网民的声音. 信息检索技术的应用,有效地提高了网络口碑研究的工 ...
- 嗨翻C语言笔记(二)
~a a中所有位都取反 a & b a中的位 与 b中的位 (都为1则1,否则为0) a | b a中的位 或 b中的位 (只要对应位一个位1则为1) a ^ b a中的位 亦或 b中的位 & ...
- 【原创】面向对象作业:选课系统中用pickle储存多个对象间组合引用关系的那些坑
转载请注明出处:https://www.cnblogs.com/oceanicstar/p/9030121.html 想直接看结论先提前列出: 1.存储一个对象,文件不是真的给你存储的了对象这种东西, ...
- jdbc学习笔记02
数据库连接池 DBCP DataBase Conection Pool:数据库连接池 如果没有数据库连接池,每一次业务都需要服务器和数据库服务器建立一次连接,业务处理完连接断开,如果有1万次业务处理, ...
- 使用zxing二维码识别
1.多二维码识别 (同一张图片中多二维码识别) 直接上代码舒服: pom文件: <!-- QR Code --> <dependency> <groupId>com ...
- jQuery最重要的知识点
1.各种常见的选择器.2.对于属性的操作.[重点] 2.1)获取或设置属性的值: prop(); 2.2 ) 添加.删除.切换样式: addClass/removeClass/toggleClass ...