前言
作为一个复制粘贴工程师,一直以来都是(可能只有我这样 o(╥﹏╥)o )
vue create hello-world
npx create-react-app hello-world
复制代码
类似这样的脚手架命令一顿操作,什么Babel啊、Postcss、各种Loader、Eslint啊Uglifyjs都一把梭好了,然鹅到底这些是怎么配置的,不满足需求的时候怎么办呢? 这些脚手架都是基于Webpack(Webpack是什么?点我)的,最近在写原生JS项目,没有了脚手架就没有Babel、autoprefixer、Uglifyjs了,那谁给我转代码,谁给我加浏览器前缀、谁给我压缩代码啊!复制粘贴工程师的自我修养告诉我不能这样,这些活还是别人干ヽ(✿゚▽゚)ノ
于是就开始了新的复制之旅
开始
先来复制一段,新建个项目,项目根目录下npm init -y
,-y就是全yes了,至于yes了啥胸弟们可以不-y试试 ︿( ̄︶ ̄)︿
项目目录下多了个package.json,里面记录了项目相关的信息。
基于Webpack我们当然要安装Webpack了
npm i webpack webpack-cli -D
复制代码
命令完成后,项目中多了一个 node_modules文件夹,该文件夹是用来存放项目中安装的依赖包,以后项目依赖的包也都会在里面。
初始化项目目录,新建src、dist、config以及index.html(html里随便写点啥比如hello world等会打开了至少不是白的就行),还有src目录下的入口文件index.js(空的即可)
初始化工作基本就完成了 webpack打包默认入口为src/index.js, 默认打包模式为 --mode development, 打包模式总共有两种:
- mode development(开发环境)
- mode production(生产环境)
现在可以在package.json -> scripts 栏目 配置build的命令
{
"name": "test-webpack-bundler",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --mode production"
},
下面太长省略了...
}
复制代码
然后执行npm run build
webpack配置工程师警告(๑•̀ㅂ•́)و✧
webpack配置之旅
先npm i webpack-dev-server html-webpack-plugin internal-ip -D
开发环境本地服务就靠webpack-dev-server了,生成html、自动插入js等就靠html-webpack-plugin了,局域网设备可通过IP访问就靠internal-ip
在config目录里新建一个webpack.dev.js
又到了复制粘贴的时候啦
const path = require("path");
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const packageConfig = require("../package.json");
const internalIp = require('internal-ip') // 借助这个实现可用局域网IP访问
const devWebpackConfig = {
mode: "development",
devtool:'#source-map',
devServer: {
port: 9527, // 指定端口号; 默认 8080
hot: true, // 热更新
host: internalIp.v4.sync(), // 可通过局域网IP访问,也可以通过 localhost 访问
open: true, // 启动本地服务后,自动打开页面
overlay: true, // 编译器错误或警告时, 在浏览器中显示全屏覆盖; 默认false
progress: true, // 是否将运行进度输出到控制台; 默认 false
contentBase: path.resolve(__dirname, "dist"), // 告诉服务器从哪里提供内容。只有在你想要提供静态文件时才需要
publicPath: "/",
// 精简终端输出
stats: {
modules: false,
children: false,
chunks: false,
chunkModules: false
}
},
entry: ["./src/index.js"],
plugins: [
new HtmlWebpackPlugin({
template: "index.html", // 指定模板html文件
title: packageConfig.name, // html的title的值,这里我从package.json里取了
inject: true, // 自动引入JS脚本的位置,默认值为 true
})
]
};
module.exports = devWebpackConfig;
复制代码
devtool详情看这里 现在在package.json -> scripts 中配置dev的命令
"dev": "webpack-dev-server --config config/webpack.dev.js --color --progress"
复制代码
现在npm run dev
吧 胸弟们熟悉的不要不要的了吧,走你
没问题我们继续,有问题···胸弟们百度一下吧
现在我们就参考Vue Cli生成的项目整理目录吧
- assets 主要是图片啊 图标啊 字体啊 之类的
- styles 就是css啦
- utils 就是工具函数了 比如写(复制)了个防抖啊、节流啊、时间格式化啊之类的扔进去,用的时候导入即可
webpack只认识js,图标、字体、css等其他的就需要各种loader拿给webpack,它才认识。
先搞定css吧,顺便把sass和scss也搞了(less同理,找对应loader即可) 随便写几句意思一下
index.html
<header class="flex-container header-wrapper">
<h1 class="title">test-webpack4-bundler</h1>
<div class="user-avatar-box">
<img class="adaptive-img" src="./src/assets/uncle.jpg" alt="" />
</div>
<ul>
<li class="list-item">1</li>
<li class="list-item">2</li>
<li class="list-item">3</li>
<li class="list-item">4</li>
<li class="list-item">5</li>
<li class="list-item">6</li>
</ul>
</header>
复制代码
src/index.js
import './styles/index.scss' // global css
复制代码
src/styles/index.scss
@import "./header.scss";
.flex-container {
display: flex;
justify-content: center;
align-items: center;
}
.adaptive-img {
width: 100%;
height: 100%;
object-fit: cover;
object-position: center;
}
复制代码
src/styles/header.scss
.header-wrapper {
flex-direction: column;
.title {
color: rgb(65, 85, 28);
}
.user-avatar-box {
width: 120px;
height: 120px;
overflow: hidden;
border-radius: 50%;
}
}
复制代码
复制粘贴
npm i css-loader style-loader sass-loader sass postcss-loader autoprefixer -D
复制代码
装一堆 看名字也知道大概是干什么的了吧 postcss-loader配合autoprefixer就可以自动加-webkit这些前缀了
(当然PostCSS还能干很多事,想要了解的话点我)
config/webpack.dev.js里,和plugins同级配置loader
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
"style-loader",
"css-loader",
"postcss-loader",
{
loader: "sass-loader",
options: {
implementation: require("sass")
// 默认使用的node-sass,这样配置就会使用dart-sass
}
}
// webpack的规定,多个loader要倒着写,比如scss文件先给sass-loader解析成css再给css-loader,以此类推
]
}
]
}
复制代码
项目根目录下创建两个文件用来配置postcss-loader和autoprefixer
.browserslistrc
> 1%
last 2 versions
not ie <= 9
复制代码
postcss.config.js
module.exports = {
plugins: {
autoprefixer: {}
}
};
复制代码
又可以npm run dev
了 已经看到我们想要的样子并且已经自动加了针对不同内核的前缀
css部分已经结束了,现在我们写点牛逼的代码吧
utils/index.js
export function $(selector) {
return document.querySelector(selector);
}
复制代码
src/index.js
import "./styles/index.scss"; // global css
import { $ } from "./utils";
import { resolve } from "path";
window.onload = () => {
const showText = "守护姨父的微笑";
setTimeout(() => {
}, 1000);
const changeTitle = () => {
let myPromise = new Promise((resolve, reject) => {
resolve();
});
return myPromise;
};
changeTitle().then(()=>{
$(".title").innerHTML = `我们要${showText}`;
const lists = [...document.querySelectorAll(".list-item")];
lists.forEach(element => {
console.log(element);
});
let [a, b, c] = ["索尼好!退果报平安", 2, 3];
console.log(a);
$(".title").innerHTML = `我们要${showText}${a}`;
})
};
复制代码
好了我们写了箭头函数、模板字符串、const声明、Promise都是es6的语法,某些不现代的浏览器不支持,所以我们需要Babel老弟帮帮我们
复制粘贴
npm i babel-loader @babel/core @babel/preset-env @babel/runtime @babel/plugin-transform-runtime @babel/plugin-syntax-dynamic-import -D
复制代码
src/index.js 头部引入垫片
import "@babel/polyfill";
复制代码
项目根目录下新建.babelrc
{
"presets": ["@babel/preset-env"],
"plugins": [
"@babel/plugin-transform-runtime"
]
}
复制代码
config/webpack.dev.js 里module>rules下增加一个loader
{
test: /\.js$/,
use: ["babel-loader"],
exclude: /node_modules/
},
复制代码
config/webpack.dev.js entry加入 @babel/polyfill
entry: ["@babel/polyfill","./src/index.js"]
复制代码
package.json -> scripts build
"build": "webpack --config config/webpack.dev.js --mode production --color --progress"
复制代码
npm run build
走一波
(babel-polyfill和babel-runtime的关系和区别大概可以看这里)
好像大概是弄完了?等等,打包出来的html文件图片引用路径好像不对,没hash值迭代了缓存不得搞死我们啊,那么下一轮复制粘贴又要开始了。
开发环境大概就这么样了吧,针对生产环境我们需要再搞点东西了 先复制一份webpack.dev.js,叫webpack.prod.js,作为生产环境的webpack配置
装,分别是解决js和html里的文件路径问题
npm i url-loader file-loader html-withimg-loader -D
复制代码
然后删除开发服务器,
config/webpack.prod.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const packageConfig = require("../package.json");
const prodWebpackConfig = {
mode: "production",
devtool: false,
entry: ["@babel/polyfill", "./src/index.js"],
output: {
path: path.resolve(__dirname, "../dist"),
filename: path.posix.join("static", "js/[name].[chunkhash].js"),
chunkFilename: path.posix.join("static", "js/[id].[chunkhash].js")
},
module: {
rules: [
{
test: /\.js$/,
use: ["babel-loader"],
exclude: /node_modules/
},
{
test: /\.(sa|sc|c)ss$/,
use: [
"style-loader",
"css-loader",
"postcss-loader",
{
loader: "sass-loader",
options: {
implementation: require("sass")
// 默认使用的node-sass,这样配置就会使用dart-sass
}
}
// webpack的规定,多个loader要倒着写,比如scss文件先给sass-loader解析成css再给css-loader,以此类推
]
},
{
test: /\.(htm|html)$/,
loader: "html-withimg-loader"
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: "url-loader",
options: {
limit: 10000,
name: path.posix.join("static", "img/[name].[hash:7].[ext]")
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: "url-loader",
options: {
limit: 10000,
name: path.posix.join("static", "fonts/[name].[hash:7].[ext]")
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: "index.html", // 指定模板html文件
title: packageConfig.name, // html的title的值,这里我从package.json里取了
inject: true, // 自动引入JS脚本的位置,默认值为 true
minify: {
minifycss: true, // 压缩css
minifyJS: true, // 压缩JS
removeComments: true, // 去掉注释
collapseWhitespace: true, // 去掉空行
removeRedundantAttributes: true, // 去掉多余的属性
removeAttributeQuotes:true, // 删除不需要引号的属性值
removeEmptyAttributes: true // 去掉空属性
}
})
]
};
module.exports = prodWebpackConfig;
复制代码
package.json -> scripts build 该用生产环境的配置build了
"build": "webpack --config config/webpack.prod.js --mode production --color --progress"
复制代码
npm run build
走一波
可以看到,html压缩过了,img路径也正确了,同时目录结构也整齐多了,文件也带了hash值
大体上完成了,后续还有一些优化,比如用指定的插件去压缩JS,CSS抽离成单个文件并优化,将根目录下的static下静态资源copy到打包目录下等,单独抽离第三方库等,就不一一说了,主要写这玩意太累了。。。大佬们好牛逼。。。。真的
如果有哪里有问题欢迎大佬们告诉我 感恩!
附上这个项目的地址里面包含了完整的配置