webpack从零搭建开发环境
什么是 webpack
使用 webpack 作为前端构建工具
- 代码转化:
TypeScript
编译成Javascript
,SCSS
编译成Css
等 - 文件优化:压缩
JavaScript
、Css
、Html
代码 压缩合并图片等 - 代码分割:提取多个页面的公共代码 提取首屏不需要执行部分的代码让其异步加载
- 模块合并:在采用模块化的项目会有很多个模块和文件,需要构建功能把模块分类合并成一个文件
- 自动刷新:监听本地源代码的变化,自动重新构建,刷新浏览器
- 代码校验:在代码被提交到仓库前需要校验代码是否符合规范,以及单元测试是否通过
- 自动发布:更新完代码后,自动构建出线上发布代码并传输给发布系统
在 webpack 应用中有两个核心
- 模块转换器:用于把模块原内容按照需求转换成新内容,可以加非 JS 模块
- 扩展模块:在 webpack 构建流程中的特定时机注入扩展逻辑来改变构建结果或做 NIIT 想要的事情
初始化项目
npm init -y
npm i webpack webpack-cli --save-dev
npm -S 是--save的缩写 是生产
npm -D 是--save-dev的缩写 是开发
webpack-cli
的目的是解析用户传递一些参数给 webpack 打包
打包
- webpack 默认支持模块的写法
commonJs
规范是 Node - 也支持 es6 规范 esmodule
- 把模块打包,解析出浏览器可以识别的代码
- 装
webpack
的时候是装的开发环境 直接webpack
是找不到的,可以使用npx
(这个命令是 npm 5.2) 之后出来的npx
是默认找node_modules
中的.bin
目录下的文件
npx webpack
- 两种模式:
开发环境
生产环境
npx webpack --mode development 开发环境不会被压缩
为了方便也可以这么写,使用 npm run
命令这个命令执行的时候默认会把 node_modules
的.bin 文件放到全局上,执行之后销毁npm run buildnpm run dev
"scripts": {
"build":"webpack --mode production",
"},
- webpack 配置文件默认叫
webpack.config.js
webpack.file.js
默认导出的是配置文件
- 入口
module.exports={ //入口 entry:path.resolve(__dirname,'./src/index.js'), //写路径都采用绝对路径 }
- 出口
module.exports={ output:{ filename:"bundle.js", path:path.resolve(__dirname,"dist"); } }
- 模式
module.exports = { mode: "development" //当前是开发模式 }
"scripts": { "build": "webpack", "dev":"webpack" }, //- 变量的形式
webpack.config.js
module.exports = (env)=>{ //env 环境变量 console.log("mode",env) //函数要返回配置文件,没返回会采用默认配置 }
package.json
"scripts": { "build": "webpack --env.production", "dev":"webpack --env.development" },
为了区分开发模式和生产模式 会新建一个 build
文件 新建一个基础配置 webpack.base.js
webpack.base.js webpack.dev.js webpack.prod.js
通过--config 指定执行的文件是哪一个。
- 可以在 base 文件合并
- 可以创建 dev,prod 分别在这两个文件中合并 base
"scripts": {
"build": "webpack --env.production --config ./build/webpack.base.js",
"dev": "webpack --env.development --config ./build/webpack.base.js"
},
- 可以通过 webpack-merge 来合并配置文件
npm i webpack-merge --save-dev
用法
if(isDev){
return merge(base,dev)
}else{
return merge(base,prod)
}
如果是开发环境,要使用 webpack-dev-server
npm i webpack-dev-server --save-dev
webpack-dev-server 是在内存中打包的不会产生实体
"scripts": {
"build": "webpack --env.production --config ./build/webpack.base.js",
"dev": "webpack-dev-server --env.development --config ./build/webpack.base.js"
},
module.exports={
mode:"development",
devServer:{ //开发服务的配置
port:3000,
compress:true, //gzip 可以提升返回页面的速度
contentBase:path.resolve(__dirname,'../dist') //webpack启动服务会在dist目录下
}
}
- 在 dist 打包自动生成 html 文件并且引入打包后的 js 内容
npm i html-webpack-plugin --save-dev
在根文件下创建 public 文件夹
plugins:[
new HtmlWebpackPlugin({
template:path.resolve(__dirname,'../public/index.html'),
filename:"index.html",
minify:!isDev&&{
removeAttributeQuotes:true, //去掉双引号
collapseWhitespace:true //去掉空格
}
})
]
- 每次打包重新生成 dist
npm i clean-webpack-plugin --save-dev
//每次打包先清空dist文件夹
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: ['**/*'] //打包之前清空目录 默认是这个配置 所有目录下的所有文件
}),
代码转化
css
先解析 css
// index.js
import './index.css'
//引入css
1.
loader
的执行顺序 默认从下往上执行 从右往左执行2.
css-loader
会解析 css 语法style-loader
会将解析的 css 变成 style 标签插入到页面中3.解析 css 需要两个
css-loader
style-loader
npm i css-loader style-loader --save-dev
转化什么文件 用什么去转 使用那些loader
loader写法 可以是[] 也可以是{}也可以是""
rules:[
{
test:/.css$/,
use:['style-loader','css-loader']
},
]
预处理器
scss
node-sass
sass-loader
npm i node-sass sass-loader --save-dev
匹配到scss结尾的文件使用sass-loader来调用node-sass处理sass文件
{
test:/.scss$/,
use:['style-loader','css-loader','sass-loader']
}
less
less-loader
stylus
stylus-loader
如果 css 里引入了 scss 文件
rules:[
{
test:/.css$/,
use:['style-loader',{
loader:'css-loader',
options:{
importLoaders:1
}
},'sass-loader']
},
]
css 加前缀
- 自动加前缀
npm i postcss-loader --save-dev
npm i autoprefixer --save-dev
需要一个配置文件 post.config.js
module.exports={
plugins:[
require("autoprefixer")
]
}
创建一个.browserslistrc
文件
cover 95%
- 这么写开发是 ok 的,但是怎么解决生产样式?
- 解析 css 的时候就不能渲染 dom
- 希望 css 可以和 js 一起加载
mini-css-extract-plugin
需要把 css 抽离
npm i mini-css-extract-plugin --save-dev
new MiniCssExtractPlugin({ //如果是开发模式就不要用抽离样式的插件
filename:"css/main.css"
})
{
test: /.css$/,
use: [
isDev?'style-loader':MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
importLoaders: 2
}
}, 'postcss-loader', 'sass-loader']
}
webpack.prod.js
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const TerserJSPlugin = require('terser-webpack-plugin');
module.exports={
mode:"production",
optimization: { //优化项
minimizer:[ //可以放置压缩方案
new OptimizeCSSAssetsPlugin(), //用了这个 js也得手动压缩
new TerserJSPlugin()
]
},
}
图片
- 压缩图片
npm i file-loader --save-dev
npm i url-loader --save-dev
{
test:/.(woff|ttf|eot|svg)/,
use:"file-loader"
},
{
test: /.(jpe?g|png|gif|jpg)$/,
use: {
loader: "url-loader",
//如果大于100k的图片继续使用file-loader
options: {
name: 'image/[contentHash].[ext]',
limit: 100 * 1024
}
}
//file-loader 默认的功能是拷贝的功能
//我希望是当前比较小的转化成base64 比以前大 好处就是不用发http请求
}
js
-
es6
转es5
但是有些 api 不是 es6 语法比如装饰器 类的属性 - babel 转化功能 vue-cli 基于 babel6 来实现的,但是现在最新 babel 是 babel7
- @babel/core 核心模块
- @babel/preset-env 把 es6 转化成 es5
- babel-loader 是 babel 和 webpack 的桥梁
总结:默认会调用
@babel/core
来转化代码 转化的时候用@babel/preset-env
将 es6 转化成 es5
{ //解析js文件 调用@babel/core
test:/.js$/,
use:"babel-loader"
},
- 创建
.babelrc
文件默认是 options 的配置
{
"presets:[
"@babel/preset-env" //从下到上执行 这个是插件包
],
"plugins":[ //从上到下执行 这个是单个插件
]
}
- 解析提案语法 类的属性
npm i @babel/plugin-proposal-class-properties -D
"plugins":[ //从上到下执行
["@babel/plugin-proposal-class-properties",{"loose":true}]
]
-
loose:true
表示宽松 this.a=1 -
loose:false
Object.definedProperty
解析装饰器
npm i @babel/plugin-proposal-decorators --save-dev
- 必须在
@babel/plugin-proposal-class-properties
上面执行
"plugins":[ //从上到下执行
["@babel/plugin-proposal-decorators",{"legacy":true}],
["@babel/plugin-proposal-class-properties",{"loose":true}]
]
- 解析高级语法 使用的 api 自动转化 并且是按需加载
"presets":[
["@babel/preset-env",{
"usageBuitIns":"usage" //按需加载
}] //从下到上执行
],
- 节约代码大小
npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime
解析jsx
npm i @babel/preset-react --save-dev
解析ts
-
ts-loader
使用typescript
库 - babel7 @babel/preset-typescript 和 typescript 库没有关系
npm i typescript
npx typescript -init 生成一个typescript文件
解析vue
vue.shims.d.ts
declare module "*.vue"{
import Vue from "vue";
export default Vue
}
npm i vue-loader vue-template-compiler -D
{
test:/.vue$/,
use:"vue-loader"
},
const VueLoaderPlugin = require("vue-loader/lib/plugin");
new VueLoaderPlugin(),
-
vue
写ts
npm i vue-property-decorator --save-dev
["@babel/preset-typescript",{
"allExtensions":true
}]
最后
了解了上面的这些webpack,基本上就可以搭建我们的开发环境了,本文结束,有什么问题和有错误的地方,欢迎大家的留言和评论,还有后续更新,下期更加精彩
- 浅谈PHP开发与Java开发的优劣势,还不知道学习方向的可以来看看
- KVM+Qemu+Libvirt实战
- 内核级虚拟化技术
- tomcat配置ROOT目录和多站点
- IntelliJ IDEA使用(一)基本设置与类、方法模板设置
- JS魔法堂:从void 0 === undefined说起
- Maven(三)在Eclipse中使用Maven与Maven坐标
- Nginx多站点设置及负载均衡
- Maven(二)Maven项目的创建(命令、myeclipse)及生命周期
- JS魔法堂:初探传说中的setImmediate函数
- 配置nginx.conf实现负载均衡
- Maven(一)初识Maven
- MySQL(十一)之触发器
- 用CSS3在火狐浏览器中实现倒影
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 【Pytorch】笔记一:数据载体张量与线性回归
- 为什么我不再用Redux了
- 【Pytorch 】笔记二:动态图、自动求导及逻辑回归
- 听说国漫最近崛起了,那我们就来爬几部国漫看看(动态加载,反爬)
- 微信小程序开发实战(25):预览图像
- 【Pytorch】笔记三:数据读取机制与图像预处理模块
- 表白利器,马赛克拼贴照片制作
- 【014期】JavaSE面试题(十四):基本IO流
- 微信小程序开发实战(24):选择图像
- 反 996 有理:催程序员交代码,写不出好软件
- 一千个不用 Null 的理由!
- WebAssembly 是 Deno 的好搭档
- Chrome开发者工具的11个高级使用技巧
- 怒爬某破Hub站资源,简单4步撸个鉴黄平台!
- 审阅“史上”最烂的代码