npm init
一般我们会用到npm里面的东西,执行以下命令生成一个package.json文件,当你安装npm包的时候会同步更新到package.json,别人拉你的项目的时候直接npm install就可以安装所有需要的npm模块,方便省事。
npm init
然后目录下有一个package.json文件
npm install webpack -D
npm install webpack-cli -D
.gitignore
新建一个.gitignore文件,把node_modules写入,这个文件是指提交git的时候忽略哪些文件。此处有一个疑问,那引入的npm包要从哪里来?其实是在打包的时候就会把用到的(不是全部)npm包里面的东西打包进去。
bundle chunks module
粗浅理解,我们编写的源文件里面会引入多个module,被webpack处理生成对应的多个chunks,chunks组成bundle,bundle就是打包后的文件,一个bundle包含多个chunks。
npx
npx解决的问题
当我们安装一个模块,可以通过以下方式执行
(1)package.json的script添加命令"server":"webpack",然后在命令行通过npm run server执行。
(2)命令行执行node-modules/.bin/webpack --version
(3)npx webpack
npx是Node自带npm模块 让项目内部安装的模块用起来更方便,npx 还能避免全局安装的模块,代码运行时,npx将模块下载到一个临时目录 使用以后再删除。
npx的原理就是运行的时候会到node_modules/.bin路径和环境变量里面 检查命令是否存在,由于npx会检查环境变量,所以系统命令也可以调用Bash 内置的命令不在$PATH里面,所以不能用。
npx一些参数
npx --no-install webpack // 强制使用本地模块不使用远程模块
npx --ignore-existing webpack // 强制使用远程模块不使用本地模块
npx node@0.12.8 -v // 指定安装模块的版本 并执行命令-v
npx -p node@0.12.8 node -v // 指定安装模块的版本 并执行命令-v
npx -p lolcatjs -p cowsay [command] // 安装多个模块 并执行命令[command]
npx -p lolcatjs -p cowsay -c 'cowsay hello | lolcatjs' -c作用是'cowsay hello | lolcatjs'都由npx执行 否则默认第一个由npx执行 第二个由Shell执行
npx https://gist.github.com/zkat/4bc19503fe9e9309e2bfaa2c58074d32 // 执行远程的代码。
尝试一次最简单的webpack打包
添加html和js文件
新建文件 index.html、index.js。
#index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>index html</title>
</head>
<body>
<div class="red">这里是index.html</div>
<script src="./index.js"></script>
</body>
</html>
#index.js
console.log("这里是index.js")
打开html,一切正常。
添加webpack.config.js文件并配置
新建webpack.config.js文件。
#webpack.config.js
const path = require('path');
module.exports = {
mode: "development",//必加
//相对于process.cwd(),process.cwd()返回的是Node.js进程的当前工作目录,此处是workplace。
entry: "./src/pages/main/index/index.js",
output: {
filename: "js/[name].[hash:8].js",//js bundle的文件名
path: path.resolve(__dirname, "../dist"),//所有类型bundle的路径 绝对路径
},
};
命令行输入以下命令开始打包
npx webpack --config webpackConfig/webpack.config.js
clean-webpack-plugin 打包前删除dist
如果我修改了index.js文件的内容,我再进行打包,就会出现两个哈希不一样的js文件。
#index.js
console.log("这里是修改后的index.js")
npm install clean-webpack-plugin -D
#webpack.config.js
const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");//引入插件
module.exports = {
mode: "development",
entry: "./src/pages/main/index/index.js",
output: {
filename: "js/[name].[hash:8].js",
path: path.resolve(__dirname, "../dist"),
},
plugins: [
new CleanWebpackPlugin()//使用插件
],
};
entry的四种格式
// 字符串 单页应用(SPA)
entry:"src/pages/main/index/js/index.js"
// 数组 多对一
entry:['src/pages/main/index/js/index.js','src/pages/main/list/js/index.js']
// 对象 多页应用(MPA)
entry:{
'pages/main/index': 'src/pages/main/index/js/index.js',
'pages/main/list': 'src/pages/main/list/js/index.js'
}
// 函数 返回以上三种格式
entry:()=>{return xxx;}
尝试打包一个多页应用
const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
mode: "development",
// 用对象的形式输入entry
entry: {
"pages/main/index": "./src/pages/main/index/index.js",
"pages/main/list": "./src/pages/main/list/index.js",
},
output: {
filename: "js/[name].[hash:8].js",
path: path.resolve(__dirname, "../dist"),
},
plugins: [new CleanWebpackPlugin()],
};
这里的name为pages/main/index,结合output的path和filename,最终bundle的路径如下图。
context
设置entry的根路径context可以少写一些重复路径
const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
mode: "development",
context:path.resolve(__dirname,"../src/pages"),//绝对路径
entry: {
"pages/main/index": "./main/index/index.js",//相对context的路径设置
"pages/main/list": "./main/list/index.js",
},
output: {
filename: "js/[name].[hash:8].js",
path: path.resolve(__dirname, "../dist"),
},
plugins: [new CleanWebpackPlugin()],
};
多页应用入口 自动化
entry: {
"pages/main/index": "./main/index/index.js",//相对context的路径设置
"pages/main/list": "./main/list/index.js",
},
如果只有一两个入口我们可以手动写,但是如果有十几个或者二十几个页面,手动写就有点麻烦了。所以我们可以通过一个函数来对路径进行处理并返回以上的格式。
新建一个文件util.js
#util.js
const fs = require("fs");
const path = require("path");
/**
* @desc: entry路径处理
*/
exports.entryFilePath = function () {
let entryFilePath = {};
// src/pages里面的文件夹
page_level_one_arr = fs.readdirSync(path.join(__dirname, "../src/pages"));
page_level_one_arr.forEach((page_level_one) => {
// mac 自动生成的.DS_Store文件 不进行处理
if (page_level_one == ".DS_Store") return;
// src/pages/main里面的文件夹
page_level_two_arr = fs.readdirSync(
path.join(__dirname, "../src/pages", page_level_one)
);
page_level_two_arr.forEach((page_level_two) => {
// mac 自动生成的.DS_Store文件 不进行处理
if (page_level_two == ".DS_Store") return;
// 存储一个目录的路径
entryFilePath[
`pages/${page_level_one}/${page_level_two}`
] = `./${page_level_one}/${page_level_two}/index.js`;
});
});
return entryFilePath;
};
以上方法是处理如图的路径,其他路径需要另外处理。至此自动打包js下的文件并按预期目录输出打包后的文件。
npm run build设置
每次都在命令行输入npx webpack --config webpackConfig/webpack.config.js进行打包有点麻烦,我们可以在package.json进行设置。
npm run build进行打包啦~
html打包
如上可以发现仅仅是对JS文件进行打包,在html中想要引用还要手动设置路径。
#index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>index html</title>
</head>
<body>
<div class="red">这里是index.html</div>
// 删除该句
<!--<script src="../../../../dist/js/pages/main/index.848d2746.js"></script>-->
</body>
</html>
下面我们安装html-webpack-plugin插件,对html进行打包,让其自动引入对应的js文件。
npm install html-webpack-plugin -D
#webpack.config.js
const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const { entryFilePath } = require("./util.js");
const htmlWebpackPlugin = require("html-webpack-plugin");// 引入插件
module.exports = {
mode: "development",
entry: entryFilePath(),
context: path.join(__dirname, "../src/pages"),
output: {
filename: "js/[name].[hash:8].js",
path: path.resolve(__dirname, "../dist"),
},
plugins: [
new CleanWebpackPlugin(),
new htmlWebpackPlugin({
//设置html源文件路径
template: path.join(__dirname, `../src/pages/main/index/index.html`),
//设置bundle路径
filename: `pages/main/index.html`,
// 设置引入哪个chunks 不写默认全部chunks
chunks: [`js/pages/main/index`],
}),
],
};
#util.js
/**
* @desc: htmlWebpackPlugin 路径处理
*/
exports.htmlWebpackPluginPath = function () {
let htmlWebpackPluginPath = [];
// src/pages里面的文件夹
page_level_one_arr = fs.readdirSync(path.join(__dirname, "../src/pages"));
page_level_one_arr.forEach((page_level_one) => {
// mac 自动生成的.DS_Store文件
if (page_level_one == ".DS_Store") return;
// src/pages/main里面的文件夹
page_level_two_arr = fs.readdirSync(
path.join(__dirname, "../src/pages", page_level_one)
);
page_level_two_arr.forEach((page_level_two) => {
// mac 自动生成的.DS_Store文件
if (page_level_two == ".DS_Store") return;
// 生成一个htmlWebpackPlugin
htmlWebpackPluginPath.push(
new htmlWebpackPlugin({
template: path.join(
__dirname,
`../src/pages/${page_level_one}/${page_level_two}/index.html`
),
filename: `pages/${page_level_one}/${page_level_two}.html`,
chunks: [`pages/${page_level_one}/${page_level_two}`],
})
);
});
});
return htmlWebpackPluginPath;
};
#webpack.config.js
const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const { entryFilePath, htmlWebpackPluginPath } = require("./util.js");//引入方法
module.exports = {
mode: "development",
context: path.join(__dirname, "../src/pages"),
entry: entryFilePath(),
output: {
filename: "js/[name].[hash:8].js",
path: path.resolve(__dirname, "../dist"),
},
plugins: [
new CleanWebpackPlugin(),
...htmlWebpackPluginPath()//引入方法
],
};
加载CSS
内联样式表
目前仅有html和js两种格式,我们来添加css的文件。
#index.css
.red{ color: red;}
在js文件中引入css文件
import './index.css';//引入css文件
console.log("这里是index.js2")
安装css-loaser和style-loader
npm install css-loader style-loader -D
配置webpack.config.js文件
const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const { entryFilePath, htmlWebpackPluginPath } = require("./util.js");
module.exports = {
mode: "development",
context: path.join(__dirname, "../src/pages"),
entry: entryFilePath(),
output: {
filename: "js/[name].[hash:8].js",
path: path.resolve(__dirname, "../dist"),
},
module: {
rules: [
{
test: /\.css$/,//匹配.css的文件
use: [
"style-loader",//样式动态的以<style>形式插入
"css-loader"//识别.css模块
],
},
],
},
plugins: [new CleanWebpackPlugin(), ...htmlWebpackPluginPath()],
};
打包后并没有产生.css文件,因为不是以link的方式引入,而是通过js动态的将样式插入到head中。
外部样式表
npm i mini-css-extract-plugin -D
#webpack.config.js
const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");//引入插件
const { entryFilePath, htmlWebpackPluginPath } = require("./util.js");
module.exports = {
mode: "development",
context: path.join(__dirname, "../src/pages"),
entry: entryFilePath(),
output: {
filename: "js/[name].[hash:8].js",
path: path.resolve(__dirname, "../dist"),
},
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,//删除style-loader 引入loader
},
"css-loader",
],
},
],
},
plugins: [
new CleanWebpackPlugin(),
...htmlWebpackPluginPath(),
//引入插件
new MiniCssExtractPlugin({
filename: "css/[name].[hash:8].css",
}),
],
};
加载图片
在css中 || 在js中 || 在html中 引入图片
npm i file-loader url-loader -D
#index.html
css中引入的图片
<div class="red">这里是index.html</div>
JS中引入的图片
<img id="J-img" src="/"></img>
html中引入的图片
<img src="./img/img.png" alt="">
<img src="~global/img/global.jpg" alt="">
#index.css
.red{
color: red;
background:url("~global/img/global.jpg");
// background:url("./img/img.png");
}
#index.js
import './index.css';
import img from "global/img/global.jpg";
console.log("这里是index.js2");
document.getElementById("J-img").src = img;
#webpack.config.js
const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const { entryFilePath, htmlWebpackPluginPath } = require("./util.js");
module.exports = {
mode: "development",
context: path.join(__dirname, "../src/pages"),
entry: entryFilePath(),
output: {
filename: "js/[name].[hash:8].js",
path: path.resolve(__dirname, "../dist"),
publicPath: "../../",//设置全局默认的公共路径
},
module: {
rules: [
{
test: /\.(png|svg|jpg|gif)$/,
use: {
loader: "url-loader",
options: {
limit: 1,
name: "global/img/[name].[ext]",
esModule: false,
//针对所有图片也可以设置路径
},
},
},
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: "../../../",//css内部的资源的路径处理
},
},
"css-loader",
],
},
// html的img路径处理
{
test: /\.(html)$/,
use: {
loader: "html-loader",
options: {
attributes: true,
},
},
},
],
},
plugins: [
new CleanWebpackPlugin(),
...htmlWebpackPluginPath(),
new MiniCssExtractPlugin({
filename: "css/[name].[hash:8].css",
}),
],
resolve: {
alias: {
global: path.join(__dirname, "../src/global"),
},
},
};
总结:
1、可以用output的publicPath来设置所有的默认引入路径
2、每个loader或者plugin都可能有自己的publicPath,可以去查找相关资料
3、其实会和乱,用../../类似的地址的时候,以上可以作为一个参考,接下来我们要开始本地开发,设置publicPath,再根据相对workplace设置路径会清晰很多。
本地 && 打包
"build": "webpack",
"server": "webpack-dev-server"
"watch":"webpack --watch"
npm run build
就是执行打包 将文件打包并生成dist文件夹
npm run watch
就是监听本地文件更改 打开文件index.html (file:///Users/TEST/src/pages/main/index/tmpl/index.html) 更改index.html的内容 刷新页面 就能看到更改
npm run server
npm i webpack-dev-server -D
启动一个本地服务器 当通过localhost:8081访问该服务器 服务器返回的内容可通过contentBase设置
devServer: {
contentBase: "src",
port: 8081
},
终端会输出一些提示
// 访问contentBase的地址
ℹ「wds」: Project is running at http://localhost:8081/
// 指output中设置的publicPath 指output的路径为/
ℹ「wds」: webpack output is served from /
// 指devServer的contentBase 即服务器返回的内容
ℹ「wds」: Content not from webpack is served from src
至此 基本的webpack已经告一段落。之后再有其他的用到的点再更。