webpack版本:4.8.3
webpack-cli版本:2.1.3
1.全局安装webpack和webpack-cli
cnpm i webpack webpack-cli -g
2.新建一个项目, 然后初始化
cnpm init
然后会生成一个package.json和 package-lock.json
3.在项目本地安装webpack和webpack-cli
cnpm i webpack webpack-cli -D
注: -D是--save-dev的缩写
-S是--save的缩写
区别:-D是只在开发环境即dev中使用,项目发布以后就不会使用到,如babel,loader等
-S是在开发和正式环境都会用到,如jq,Vue等
4.打包第一个js文件
在根目录新建一个hello.js文件,然后执行
webpack hello.js hello.bundle.js
会得到一个警告一个错误
这是因为webpack4与之前不太一样
webpack4.x的打包已经不能用
webpack 文件a 文件b
的方式,而是直接运行
webpack --mode development(开发环境)
或者
webpack --mode production(发布模式)
,这是 webpack 4 引入的模式,包括 development、production、none 三个值,我们不传入值的话,默认使用 production进行打包。
我们可以在package.json,script字段中添加以下设置:
"dev":"webpack --mode development", "build":"webpack --mode production"
这样,我们就能直接使用命令 npm run dev 或 npm run build 来进行文件的打包处理。
webpack4.x会以项目根目录下'./src/index.js'作为入口,单单创建src文件夹或者没有index.js文件都会报错,输出路径是'./dist/main.js',dist目录及main.js会自动生成。
5.打包一个css文件
安装
css-loader:使webpack可以处理css文件
style-loader:新建一个style标签,把css-loader处理过的文件放进去,然后插入到HTML标签中
第一种方法:
在js文件中引入css文件,然后在文件名之前添加对应的loader
require('style-loader!css-loader!./style.css')
第二种方法:
在执行webpack命令时添加
webpack --mode development --module-bind "css=style-loader!css-loader"
其他的一些参数
--watch:监控文件变化,一旦文件有变化,就重新构建。但默认情况下,watch 选项是禁用的。
--progerss:会出现打包过程,有百分比进度条
--display-modules:会把所有打包的模块列出来
--display-reasons:会把打包的原因列出来
第三种方法:
添加webpack配置文件,稍后会写出。
6.添加配置文件
webpack4学习了parcel的0配置,所以也可以不需要配置文件
这里webpack的配置文件并没有太大变化
// 单入口文件
const path = require('path')
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'main.js'
}
}
// 多入口文件
const path = require('path')
module.exports = {
entry: {
main: './src/index.js',
a: './src/a.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
}
}
注意:1.输出路径是path.resolve(__dirname, 'dist')
2.多文件的输出文件名不能固定
3.如果不写入口出口路径则使用webpack4默认的路径
7.添加加载loaders
1.预处理css,less
安装less,less-loader,css-loader,style-loader,postcss-loader和autoprefixer
cnpm install less less-loader css-loader style-loader postcss-loader autoprefixer -D
然后添加模块,规则
module: {
rules: [
{
test: /\.less$/,
loader: 'style-loader!css-loader!postcss-loader!less-loader' // 从右到左执行,所以注意顺序
}
]
}
为了加webkit等前缀需要在webpack.config同级下创建一个postcss.config.js文件导入autoprefixer自动补全
module.exports = {
plugins: [
require('autoprefixer')
]
}
还需在package.json文件中添加判断浏览器版本
"browserslist": [
"> 1%", // 全球浏览器使用率大于1%,最新两个版本并且是IE8以上的浏览器,加前缀
"last 2 versions",
"not ie <= 8"
]
8.加入babel对es6语法进行转译
cnpm install babel-loader babel-core babel-preset-env --save-dev
{
test: /\.js$/, // 匹配js文件
loader: 'babel-loader',
exclude: path.resolve(__dirname, 'node_modules'), //匹配时忽略这个目录,提高打包速度
include: path.resolve(__dirname, 'src'), // 匹配时查找的范围
query: {
presets: ['env']
}
}
9.开启实时更新
安装wbepack-dev-server
cnpm i webapck-dev-server -D
为了每次编译完成后删除上次打包的结果,添加删除插件clean-webpack-plugin,但是他也会删除我们的index.html,所以还需要安装自动生成html插件
cnpm i clean-webpack-plugin html-webpack-plugin -D
const Webpack = require('webpack')
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// devServer和plugins是与module同级的
entry:,
output: ,
module: {
rules: []
},
devServer: {
// 设置服务器访问的基本目录
contentBase: path.resolve(__dirname, 'dist'), //最好设置成绝对路径
// 设置服务器的ip地址,可以是localhost
host: 'localhost',
// 设置端口
port: 8090,
// 设置自动打开浏览器
open: true,
// 设置自动更新
hot: true
},
plugins: [
new Webpack.HotModuleReplacementPlugin(),
new CleanWebpackPlugin(['dist']), //传入数组,指定要删除的目录
new HtmlWebpackPlugin({
template: './index.html', // 会与根目录下的index.html相关联,把根目录下index的东西都放到生成的HTML中
filename: 'index.html', // 生成的HTML名,路径为上面output中的path,不填默认是index.html
title: '测试webpack',
hash: true,
chunks: ['main'], // 多页面分别引入自己的js
minify: {
collapseWhitespace: true, //折叠空白区域 也就是压缩代码
removeComments: true, //移除HTML中的注释
}
})
]
注意:热更新只针对js文件和样式文件,html不能热更新
10.仔细讲下html-webpack-plugin
多页面时需要写多个new HtmlWebpackPlugin
new HtmlWebpackPlugin({
template: './index.html', // 会与根目录下的index.html相关联,把根目录下index的东西都放到生成的HTML中
filename: 'index.html', // 生成的HTML名,路径为上面output中的path,不写默认为index.html
title: '测试webpack',
hash: true,
//inject: 'body', //指定链接注入在<head>标签中还是<body>标签中,为false值时表示不自动注入文件中,需要手动设置
chunks: ['main'], // 多页面分别引入自己的js
minify: {
collapseWhitespace: true //折叠空白区域 也就是压缩代码
}
}),
new HtmlWebpackPlugin({
template: './index.html', // 会与根目录下的index.html相关联,把根目录下index的东西都放到生成的HTML中
filename: 'a.html', // 生成的HTML名,路径为上面output中的path,不写默认为index.html
title: '测试webpack',
hash: true,
//inject: 'body', //指定链接注入在<head>标签中还是<body>标签中,为false值时表示不自动注入文件中,需要手动设置
chunks: ['main', 'a'], // 多页面分别引入自己的js
minify: {
collapseWhitespace: true //折叠空白区域 也就是压缩代码
}
})
还可通过这种方式自己引入
<% for (var chunk in htmlWebpackPlugin.files.chunks) { %>
<script type="text/javascript" src="<%=htmlWebpackPlugin.files.chunks[chunk].entry %>"></script>
<% } %>
11.添加vue
安装vue
cnpm install vue -S
安装vue-loader
cnpm install vue-loader -D
创建一个.vue后缀的文件,然后修改main.js文件
import Vue from 'vue'
import App from './app.vue'
const root = document.createElement('div')
document.body.appendChild(root)
new Vue({
render: (h) => h(App)
}).$mount(root)
然后修改webpack.config文件,添加vue-loader
注意:vue-loader15.0版本之后需要独立引入VueLoaderPlugin
const VueLoaderPlugin = require('vue-loader/lib/plugin')
{
test: /\.vue$/,
loader: 'vue-loader'
}
如果你没有安装css预处理,或者在style部分没有添加lang=*
,这时打包会报错
明显这是未对vue文件中的style部分正确的编译,所以安装vue-style-loader并添加loader
cnpm install vue-style-loader -D
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
]
},
注意:如果在main.js中的写法和vue-cli官方脚手架一样是这样的
new Vue({
el: '#app',
components: {App},
template: '<App/>'
})
则运行dev会出现警告
如果在代码中要使用到template编译模版(比如传入一个字符串给 template 选项,或挂载到一个元素上并以其 DOM 内部的 HTML 作为模板),则需要完整版的vue。
当使用 vue-loader 或 vueify 的时候,*.vue 文件内部的模板会在构建时预编译成 JavaScript。你在最终打好的包里实际上是不需要编译器的,所以只用运行时版本即可。
因为运行时版本相比完整版体积要小大约 30%,所以应该尽可能使用这个版本。如果你仍然希望使用完整版,则需要在webpack.config里配置一个别名:
module.exports = {
// ...
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
}
}
12.在vue文件里添加图片
在vue文件中添加图片,然后打包会报错
提示我们缺少file-loader,安装即可,且不用添加loader到webpack.config文件
cnpm i file-loader -D
打包时对图片的编译我们使用url-loader,他会将图片转为base64格式添加到网页中,url-loader也依赖于file-loader,所以也需要安装file-loader
cnpm i url-loader file-loader -D
{
test: /\.(gif|jpg|jpeg|png|svg)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 1024, //表示图片最大为1024KB
name: '[name].[ext]' // 生成的文件名
}
}
]
}
13.根据多环境选择不同的配置
安装cross-env
cnpm i cross-env -D
修改package.json文件
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "cross-env NODE_ENV=development webpack-dev-server --mode development",
"build": "cross-env NODE_ENV=production webpack --mode production"
},
这里的NODE_ENV会添加到process.env上,怎么添加呢?
const isDev = process.env.NODE_ENV === 'development'
const devAPI = '"http://localhost:8080"'
const proAPI = '"http://localhost:3000"'
// 注意一定是单引号加双引号的形式
...
plugins: {
...
new Webpack.DefinePlugin({
'process.env': {
NODE_ENV: isDev ? '"development"' : '"production"',
API_HOST: isDev ? devAPI : proAPI
}
})
...
}
另外可以将整个对象命名为config,然后根据isdev去给config添加配置,最后再将config暴露出去
const config = {......}
if(isDev){
config.devtool = '#cheap-module-eval-source'
}
module.exports = config
14.将css单独打包
安装extract-text-webpack-plugin
注意:webpack4中需要使用的extract-text-webpack-plugin版本比较高,需要指定版本
查看包的所有版本
cnpm view extract-text-webpack-plugin versions
安装包的最新版本
cnpm i extract-text-webpack-plugin@next -D
const ExtractTextPlugin = require('extract-text-webpack-plugin')
...
{
test: /\.less$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
'css-loader',
{
loader: 'postcss-loader',
options: {
sourceMap: true
},
},
'less-loader'
]
})
}
...
plugins: {
new ExtractTextPlugin({
filename: 'css/app.[hash].css',
chunkFilename: 'css/app.[contenthash].css'
}
webpack4中extract-text-webpack-plugin已经不再被推荐使用,推荐使用新的插件mini-css-extract-plugin
安装mini-css-extract-plugin
cnpm i mini-css-extract-plugin -D
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
...
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
{
loader: 'postcss-loader',
options: {
sourceMap: true
},
},
'less-loader'
]
},
...
new MiniCssExtractPlugin({
filename: 'static/css/app.[hash].css',
chunkFilename: 'static/css/app.[contenthash].css'
})
15.将第三方库单独打包(不是很明白)
因为CommonsChunkPlugin被删除, 改为内置的api--optimization,同plugins同级
...
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
name: 'vendor',
chunks: 'initial',
minChunks: 2
},
}
}
},