webpack4想使用命令行的话,需要安装webpack-cli
,这个webpack-cli
是在命令输入webpack
等指令操作的基础;可以加上npx
即如:npx webpack
这样来调用
npx webpack <entry>
所以不影响的话,可以全局安装,这样就不需要每次都加上npx
了
npm install webpack-cli -g
或者说不要全局安装,直接装在项目里,然后配置package.json
的script
也可以
需要说的是在命令行使用webpack
指令时,其实是在执行webpack.config.js
里的配置,单独使用webpack
时其实是执行了webpack.config.js
文件,而webpack
后面加上的指令,其实也是配置项,但是优先级高于webpack.config.js
,如webpack
里的
和在
webpack.config.js
也可以配置,但如果你给出这些配置的话,就会覆盖掉webpack.config.js
里的配置
首先,webpack允许在入口文件直接引入其他不是js的文件,当然想要有作用还必须安装各种loader,如引入CSS文件,在入口js文件,可以直接这样写
/* style.css */
body {
background-color: red;
}
/* index.js */
require('./style.css')
或者这样写,webpack同时支持直接使用ES6的模块化和Nodejs的模块化
/* index.js */
import './style.css'
webpack从入口文件就可以看到这个css文件,并且做出处理,当然如果没有loader就会报错,差不多如下
Module parse failed: Unexpected token (x:x)
You may need an appropriate loader to handle this file type,
currently no loaders are configured to process this file.
See https://webpack.js.org/concepts#loaders
所以需要安装loader
npm install -D style-loader css-loader
在webpack.config.js
配置loader
module.exports = {
module: {
rules: [
{ test: /\.css$/, use: ['style-loader', 'css-loader'] }
]
}
}
注意,要想处理css文件,并成功把样式运用到页面上,需要这两个loader,缺一不可,webpack看到css文件后第一先交给css-loader处理,css-loader如果没有,只有style-loader的话也会报和上面同样的错误信息,因为没有东西可以接受这种文件,而style-loader是把css-loader处理后的样式应用到引用这个js文件html文件的style标签里,如下面index.html文件直接引用打包好的bundle.js文件,而如果没有style-loader的话,系统没有报错,但是样式是没有应用的!
就是在打包的时候,把css抽取到一个独立的文件,而不是在bundle.js里。这里需要用到一个插件mini-css-extract-plugin
,以下是它的地址
https://github.com/webpack-contrib/mini-css-extract-plugin
大概是这样用的,注意用的时候是取代style-loader
或者vue-style-loader
之类的最后应用型的loader,即css的loader处理链的最后一个(代码上看是第一个)
npm install -D mini-css-extract-plugin
let MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
module: {
rules: [
/*
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
*/
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader']
},
{
test: /\.styl$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'stylus-loader']
}
]
},
plugins: [new MiniCssExtractPlugin()]
}
但是这样子提取的css是没有被压缩的,如果想压缩需要安装优化插件
npm install -D optimize-css-assets-webpack-plugin
之后在配置文件配置
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
// .....
optimization: {
minimizer: [
new OptimizeCSSAssetsPlugin({})
]
},
plugins: [
//........
这样生成的css就是被压缩的了
webpack也可以处理静态资源,当你在入口文件导入图片时,webpack可以把这个图片导出到dist目录,这个功能需要使用file-loader
npm install file-loader -D
在webpack.config.js
里,添加规则
{
test: /\.(png|jpg|jpge|svg|gif)$/,
use: [
{
loader: 'file-loader'
}
]
}
例如在入口文件这样
import Logo from './logo.png'
我们打包后,在dist目录就会出现那个图片,但是图片的名称就不是上面的logo.png了,而是例如像65438e39703c520115768e7ebf0e31f3.png了,其实上面的那一串就是Logo
的值。当你只使用了css-loader
时,当你的css文件里有,如url()
的值引入图片时,是会引入失败的,但当你有了file-loader
后,配合css-loader
它会在css里差不多像这样引入url(65438e39703c520115768e7ebf0e31f3.png)
图片
在有file-loader
的基础上,可以用image-webpack-loader
或者url-loader
来进一步处理了
npm install @babel/core babel-loader @babel/preset-env -D
在webpack.config.js
里配置loader
module.exports = {
module: {
rules: [{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader"
}]
}
}
在root目录下创建.babelrc
配置文件,填入如下
{
"presets": ["@babel/preset-env"]
}
之后项目打包时就可以转化为ES5了
其实就是用webpack-dev-serer
,它会在本地打开一个端口,做为开发的静态服务器,而静态服务器的根路径就是dist
目录,就是打包后bundle
所在的目录,但是需要注意的是,这种方式打包的bundle是存在于内存里的,一旦服务关掉,打包的内容就会摧毁
npm install webpack-dev-server -D
在webpack.config.js
里对象的第一层加入下面属性
devServer: {
contentBase: path.join(__dirname, './dist'), // 指定静态目录
port: 8848 // 指定端口
}
启动服务
webpack-dev-server --open
但是,webpack默认只认得js文件,就算打开了一个静态服务,里面的打包的内容也只有bundle.js
,看不到页面效果的,所以需要一个index.html
去引入bundle.js
,所以,现在问题是怎么才可以让打包后的文件除了有bundle.js
还有index.html
,并且改HTML文件引入了bundle.js
文件呢?
这时需要一个插件HtmlWebpackPlugin,简单使用如下
npm install html-webpack-plugin -D
// webpack.config.js
let HtmlWebpackPlugin = require('html-webpack-plugin')
// .....
plugins: [
new HtmlWebpackPlugin()
]
// .......
默认的话它会帮你创建以一个html文件,但是这个文件可能并不是你想要的,所以它也提供了一个接口,让你用自己的html模板
// .....
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, './public/index.html')
})
]
// .......
关于HtmlWebpackPlugin怎么使用可以看https://webpack.docschina.org/plugins/html-webpack-plugin
这个时候,我们继续使用webpack-dev-server
,在命令行使用
webpack-dev-server --open
打开浏览器,就可以看到页面效果了,并且,这个时候只要你修改了webpack依赖图的任何一个文件并保存后,不用手动刷新浏览器,它会自动刷新
注意:自动刷新并不是热替换,热替换甚至不需要刷新
sourcemap是用于帮助开发者发现bundel的BUG是由哪个原文件造成的,不用它的话,浏览器报错会直接报bundel的位置,这样的话你是很难知道找到问题的根源的,所以需要sourcemap。在webpack.config.js
里配置devtool
module.exports = {
mode: /*..........*/,
entry: {/*..........*/},
output: {/*..........*/},
devtool: 'inline-source-map'
}
之后执行打包操作后,打包后的文件下方会出现类类似
/*# sourceMappingURL=data:application/json;charset=utf-8;base64.........*/
如果打包后的文件执行后有报错,会在控制台有报错误原位置,即打包前的位置
可以把css用到的所有px
单位换成rem
单位,只需要安装两个包
npm install -D px2rem px2rem-loader
在webpack.config.js里面加入px2rem-loader
// ......
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
{
loader: 'px2rem-loader',
options: {
remUnit: 75,
remPrecision: 8
}
}
]
}
]
}
// ......
配置项可以参考 https://github.com/songsiqi/px2rem
资料 https://github.com/css-modules/css-modules
css-loader支持 https://github.com/webpack-contrib/css-loader#modules
由于有vue-loader,所以CSS Modules可以完美地运用在vue文件上,当然还需要借助css-loader
需要用到css-loader
,在里面配置
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: {
// 自定义类名生成规则,里面的[]里的值是变量,会被替换的
localIdentName: '[path][name]---[local]---[hash:base64:10]'
}
}
}
]
}
这里可以看怎么配置自定义类名生成规则 https://github.com/webpack/loader-utils#interpolatename
比如我在css文件下填入
:local(.text) {
color: pink;
}
现在打包后的css代码就是
.style---text---YuTc9Us6xQ {
color: pink;
}
这是因为我上面配置了类名转化规则
localIdentName: '[path][name]---[local]---[hash:base64:10]'
在webpack.config.js
里做如下配置
resolve: {
alias: {
'@': path.join(__dirname, './src')
}
}
现在想引入src
下的内容就可以直接import('@/......')
这样引入了
使用DefinePlugin这个插件,可以在打包编译时,把一些变量替换为我们自定义的数值,这个对于区分开发和生产很有帮助
const webpack = require('webpack')
//............
plugins: [
new webpack.DefinePlugin({
PRODUCTION: JSON.stringify(true),
})
]
如这里定义了PRODUCTION
变量,但是需要注意的是,该变量不会在webpack.config.js
里生效,就像process.env.NODE_ENV
一样
https://webpack.docschina.org/plugins/define-plugin
除了使用插件,也可以使用命令行,定义我们的npm script为
"scripts": {
"build": "webpack --config webpack.prod.js --define PRODUCTION=true"
}
这个--define
会覆盖掉插件里的配置,我们可以跟据需求去改变npm script
npm install vue-loader vue-template-compiler -D
在webpack.config.js
里配置loader,需要把style-loader
替换为vue-style-loader
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
}
// other vue-loader options go here
}
},
{
test: /\.css$/,
use: [
'vue-style-loader', // 这里不是style-loader了
'css-loader'
]
}
配置Vue插件,在webpack.config.js
头部增加这个
const VueLoaderPlugin = require('vue-loader/lib/plugin');
//...
plugins: [
new VueLoaderPlugin(),
]
//...
但是这样生成的文件是没有css的,如果需要提取css,可以用上面说的MiniCssExtractPlugin
,在vue-loader
之前引入
// ..................
{
test: /\.css$/,
use: [
'vue-style-loader',
MiniCssExtractPlugin.loader,
'css-loader'
]
}
// ............
npm install tailwindcss
npm install postcss-loader -D
之后配置webpack
//............
{
test: /\.css$/,
use: [
'vue-style-loader',
MiniCssExtractPlugin.loader,
'css-loader',
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: [
require('tailwindcss'),
require('autoprefixer')
]
}
}
]
}
//...........
之后创建tailwindcss.css
@tailwind base;
@tailwind components;
@tailwind utilities;
之后把tailwindcss.css
全局引入到项目里,webpack就会把其打包
为了让webpack针对不同的环境,采取不同的打包方式,有几种方式来区分开发环境和生产环境
原本我们的webpack.config.js
文件是导出一个对象的,我们需要改变这个做法,改成导出一个返回原来配置对象的一个函数
let config = {
entry: /*...........*/,
output: //.............
//....................
}
// 导出函数
module.exports = (env, argv) => {
return config
}
介绍地址 https://webpack.docschina.org/configuration/configuration-types#exporting-a-function
可以看到该函数传入两个参数(env, argv) => {}
,
env
是在CLI传入的环境选项,具体配置看https://webpack.docschina.org/api/cli/#%E7%8E%AF%E5%A2%83%E9%80%89%E9%A1%B9argv
可以i获取在CLI传入参数,如在CLI这样写webpack --mode=production
,那么argv
就可以获取到值,如argv.mode
就可以获取到production
所以我们可以跟据这个来区分开发环境或者是生产环境,首先在package.json的npm script里配置
{
"scripts": {
"build": "webpack --mode=production --env.production",
"build(dev)": "webpack --mode=development --env.production=false"
}
}
在webpack.config.js
里这样写
module.exports = (env, argv) => {
let config = {
entry: /*...........*/,
output: //.............
//....................
}
if (argv.mode === 'development') {
console.log('========== development ===========');
console.log(env.production);
console.log(process.env.NODE_ENV);
console.log('========== development ===========');
config.mode = 'development'
config.devtool = 'inline-source-map'
config.devServer = {
contentBase: path.join(__dirname, './dist'),
port: 8080
}
//...........
}
if (argv.mode === 'production') {
console.log('========== production ===========');
console.log(env.production);
console.log(process.env.NODE_ENV);
console.log('========== production ===========');
config.mode = 'production';
//...........
}
return config;
};
把config对象定义在函数里面,主要是为了让config里的配置可以用到env
或者argv
参数;
上面log的结果可以看到process.env.NODE_ENV
并不会生效,这是因为这是在配置文件里,需要在src
下的文件才可以按预期使用process.env.NODE_ENV
https://webpack.docschina.org/guides/production/#%E6%8C%87%E5%AE%9A-mode
如果想在webpack配置文件中访问当前环境变量,可以用env.production
来代替,参考如下 https://github.com/webpack/webpack/issues/2537比如,在我们想在生产环境和开发环境使用不同的loader处理同种文件,如css文件,可以这样
{
test: /\.css$/,
use: [
env.production===true?MiniCssExtractPlugin.loader:'style-loader',
'css-loader'
]
}
https://webpack.docschina.org/guides/production/#cli-%E6%9B%BF%E4%BB%A3%E9%80%89%E9%A1%B9
把原来的webpack.config.js
去掉,换成另外3个
webpack.common.js
webpack.dev.js
webpack.prod.js
webpack.common.js
里配置了生产环境和开发环境都需要的共同配置,如入口文件,出口,插件,loader等等,而webpack.dev.js
和webpack.prod.js
都各种配置了各自环境的配置,但是,我们需要使用工具把webpack.common.js
的内容加到另外两个文件中
npm install webpack-merge
在webpack.common.js
里照常和webpack.config.js
一样,输出一个配置对象,另外两个如下:
webpack.dev.js
const path = require('path')
const merge = require('webpack-merge')
const common = require('./webpack.common.js')
module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
devServer: {
contentBase: path.join(__dirname, './dist'),
port: 8080
}
//..........
})
webpack.prod.js
const merge = require('webpack-merge')
const common = require('./webpack.common.js')
module.exports = merge(common, {
mode: 'production'
})
mode为production和development的区别是,打包出来的bundle有没有压缩