现在vue、react很流行,新项目基本用这些新框架,组件化开发确实是趋势,但是他们再怎么发展也离不开构建工具,顶多在webpack等工具上进行再封装。现在vuecli3出来后,我感觉学习成本反而变高了,直观感觉就是文档不清爽,知识零碎。其实回到本源,vuecli3就是基于webpack来的,而且webpack本身非常好学,可以由浅到深,逐步深入。你可以不用学vue、react,只要你会html+css+js就可以用上这个打包工具。很多人不懂webpack是因为一开始就没接触过,然后最先接触的反而是vue或者react框架,结果组件api已经学晕了,突然听说这个其实是webpack的东西,一下就更懵了,所以在不懂原理的情况下,别人的包装让你更加的迷茫。有些人只想会用就行,有些人是有点搞不懂的就想搞明白。那如果你是个前端,想搞清楚本质本源的东西,真的建议你学下webpack。就从这篇入门开始吧,一小时入门webpack
本文是基于前面两篇文章来的,每一篇都不长,照着敲代码会很容易上手。一小时入门webpack,Webpack 实战入门系列(二):插件使用及热更新打包,代码已经上传到github,每节课的代码都放在独立的文件夹里,而且都是基于前面一节累加变化,所以完整的代码就是最新的教程讲解里。最好是自己动手敲出来,如果有需要可以下载下来参考:https://github.com/bridgeToVillage/webpack-learning。开始本节前,先将第二节最终代码拷贝一份,放在新建的文件夹section three。
前面第一篇提到过webpack.config.js文件中的mode这个配置参数用来指定当前的运行环境的,这个配置是webpack4提出来的,它有三个值:"production" | "development" | "none",production就是生产环境,即最终部署环境;development是开发环境;none即不指定环境因素,默认是production。开发和生产环境还是有很大区别的,按官网说法,在开发环境中,我们需要具有强大的、具有实时重新加载或热模块替换能力的 source map 和本地服务。而在生产环境中,我们的目标则转向于关注更小的输出文件,更轻量的 source map,以及更优化的资源,以改善加载时间。这里提到的souce map,意思就是资源地图,后面进阶部分会讲到,你可以上官网查下。
刚刚讲了两种环境的区别,主要是为了强调把两种环境的配置分开管理的重要性。那问题来了,用两个配置,那把webpack.config.js拷贝一份,将mode分别设置为两个环境不就可以了?这没问题,但是也可以将公用部分抽出来,在各个环境中引用公用部分,这样管理起来更方便。
这里就要提到一个工具:webpack-merge,可以专门用来合并webpack配置,可以通过npm安装;
npm install --save-dev webpack-merge
在根目录新建一个webpack.common.js文件,把webpack.config.js文件内容拷贝一份进去,删掉devServer、watch部分,只留下公用部分。
然后将webpack.config.js重命名为webpack.dev.js,再将内容修改为以下内容:
'use strict'
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
devtool: 'inline-source-map',
watch: true,
devServer: {
contentBase: './dist',
hot: true
}
});
再新建一个webpack.prod.js文件,即生产环境配置,输入以下内容:
'use strict'
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {});
修改npm scripts,将原来的启动配置修改下,将dev配置修改为
"dev": "webpack-dev-server --config webpack.dev.js --open"
因为之前都是默认从webpack.config.js中启动不用写文件名,现在开发和生产环境分开,就要将启动指向文件标名。dev代表开发环境,我们开发时就运行 npm run dev看浏览器运行效果。那么构建的时候,就要调用生产环境的配置了,在原来的构建节点build后面加上启动文件就行。
"build": "webpack --config webpack.prod.js"
然后可以运行下npm run dev看下效果,没问题
再运行下npm run build打包,也是没问题的。
总结下,就是将公用部分抽出来独立,像loader及插件这种经常会添加修改的就单独放,后期只修改common.js,应用到开发、生产环境,就在对应的配置文件中merge这个工具合并就是一个完整配置了。这样即进行了环境区分,而且公共配置被抽离,实现了互不干扰也不会增加工作量。
目前我们打包后,js代码还有样式全输出到index.js文件中,前面我们在讲到图片构建时,将图片放在样式中,然后通过url-loader打包成base64数据,所以整个的输出文件中就看起来一堆的东西,分不清你我,很混乱。这里就讲到一个插件ExtractTextWebpackPlugin,可以将样式与js分离。
npm install --save-dev extract-text-webpack-plugin
接下来要注意了,因为我们已经将生产和开发环境的配置进行了分离,而且这个插件是要在生产环境,也就是构建的时候发挥作用,所以先将之前在公用配置文件webpack.common.js中的样式相关loader删掉并移植到webpack.dev.js文件中,最后在webpack.prod.js文件中应用此插件。直接上代码,三个配置文件具体代码如下:
'use strict'
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
index: './src/index.js',
},
output: {
path: path.join(__dirname,'dist'),
filename: 'index.js'
},
plugins: [
new HtmlWebpackPlugin({
title: 'leaningwebpack',
filename: 'webpack-index.html',
favicon: 'webpack.ico'
}),
new webpack.HotModuleReplacementPlugin()
],
module: {
rules: [
{
test: /.js$/,
use: 'babel-loader',
exclude: /node_modules/
},
{
test: /.(jpg|png|gif|jpeg)$/,
use: [{
loader:'url-loader',
options: {
limit:160000,
name: 'imgs/[name].[hash].[ext]'
}
}]
}
]
}
}
'use strict'
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
devtool: 'inline-source-map',
watch: true,
devServer: {
contentBase: './dist',
hot: true
},
module: {
rules: [
{
test: /.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /.less$/,
use: [
'style-loader',
'css-loader',
'less-loader'
]
},
]
}
});
'use strict'
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = merge(common, {
plugins: [
new ExtractTextPlugin({filename: "style.css"})],
module: {rules: [
{
test: /.less$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: ['css-loader', 'less-loader']
})
}]
}
});
然后运行npm run build,就会看到在dist目录下生成了样式文件:style.css,这个文件在html文件中被引用了。我们运行npm run dev时,它会走开发环境的配置,仍然可以正常解析样式文件。
接下来讲最后webpack入门的最后一个知识点:清理输出文件。我们可以看到在dist文件夹里,有一些历史文件index.html,这是我在webpack.common.js文件里修改了东西,输出文件变了,但是之前的文件仍然会存在,这样日积月累就会有很多垃圾。这个比较简单,安装一个插件,引用一下就行了,记住,这个也是生产环境中配置。
npm install clean-webpack-plugin --save-dev
const CleanWebpackPlugin = require('clean-webpack-plugin');
plugins: [
new CleanWebpackPlugin(),
new ExtractTextPlugin({filename: "style.css"})],
代码我就不写完整了,应该能明白怎么回事了吧。然后运行npm run build,看下效果。
结果报错了:CleanWebpackPlugin is not a constructor。
在网上找了下,插件引用需要这么写:
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
{CleanWebpackPlugin}这是es6的新语法,将变量直接写入大括号就是一个对象了。为什么要这么写呢?可以看看这个插件的源码,在依赖包里找到这个文件
exports.CleanWebpackPlugin = void 0;
class CleanWebpackPlugin = { ... }
exports.CleanWebpackPlugin = CleanWebpackPlugin;
也就是说,这个插件导出的是一个变量exports.CleanWebpackPlugin,但是我们需要的是一个类CleanWebpackPlugin ,所以加上括号就可以了,我个人觉得这是插件的一个bug。
修改好后,再运行npm run build就可以看到效果了,dist目录下之前的文件删除了,生成了新文件。
● 一小时的时间,上手 Webpack● Webpack 实战入门系列(二):插件使用及热更新打包● 最简实现Promise,支持异步链式调用(20行)
·END·