Parcel是什么
Parcel 是一个可用于构建网站前端应用(如React, Vue)和npm包(如React组件库)构建工具
比起大名鼎鼎的Webpack,它所带来的便是开箱即用。
许多时候,我们并不需要对项目的构建过程进行深度定制。此时使用Parcel的优势就体现出来了。我们不需要写一堆Webpack的配置,即使用脚手架生成,它也会在我们的源代码仓库中留下一堆配置文件。
此时便是Parcel大显身手的时刻,干净利落地打包。
Parce快速入门
mkdir parcel-start && cd parcel start
yarn init -y
接着便是安装Parcel依赖
yarn add -D parcel
接下来,我们需要一个入口文件和一个脚本文件,除此之外,如果有一个全局的样式文件,那就更美妙了
src/index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>A simple Parcel App</title>
<link rel="stylesheet" href="global.less" />
</head>
<body>
<script type="module" src="index.ts"></script>
</body>
</html>
src/index.ts
const appRootEl: HTMLDivElement = document.createElement("div");
appRootEl.id = "app-root";
appRootEl.innerHTML = "Hello, world";
document.body.appendChild(appRootEl);
global.less
#app-root {
background-color: fade(pink, 20%);
}
万事俱备,只欠东风,现在就让它跑起来。这极其容易,只要给Parcel一个打包的入口,那么它能替你办好剩下的一切
yarn parcel src/index.html
访问http://localhost:1234 按照预期,我们看到的页面应该是这样的
作为入口的
index.html引入了index.ts,创建了一个内容为Hello, world的div元素。同时入口也引入了global.less,在Less中,我们使用了fade 函数来改变了粉色的透明度。
显然,我们并没有做任何关于Typescript和Less的配置,仅仅只是创建了这两个语言相关的文件。Parcel就非常智能地做到了.ts -> .js和.less -> .css的转换,并将他们打包。
React和Vue
作为目前前端主流框架的React和Vue,他们都对Javascript语法进行了扩展,因此,如果想要完整体验他们带来的便利,离不开构建工具的帮助。 因此,Parcel也将他们囊括其中了。
React
在这之前我们需要安装react和react-dom
yarn add react react-dom
在React中,除了React组件,我们还需要一些方案支持样式,最经典的就是CSS modules。
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Parcel React App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="index.jsx"></script>
</body>
</html>
src/index.jsx
import ReactDOM from "react-dom";
import { App } from "./App";
const app = document.getElementById("app");
ReactDOM.render(<App />, app)
App.jsx
import * as classes from './App.module.less';
export function App() {
return <h1 className={classes.app}>Hello React</h1>;
}
global.less
#app-root {
width: 100%;
height: 100%;
}
App.module.less,Parcel约定,*.module.结尾的文件,为 CSS module
.app {
font-size: 23px;
color: fade(pink, 60%);
}
最后就是让它们组合到一起跑起来
yarn parcel src/index.html
Vue
同样地,我们安装依赖
yarn add vue
``` html
`index.html`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Parcel Vue App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="index.js"></script>
</body>
</html>
index.js
import { createApp } from "vue";
import App from "./App.vue";
const app = createApp(App);
app.mount("#app");
App.vue
<template>
<button @click="increment" class="app">
Count is: {{ state.count }} Double is: {{
state.double }}
</button>
</template>
<script>
import { reactive, computed } from "vue";
export default {
setup() {
const state = reactive({
count: 0,
double: computed(() => state.count * 2),
});
function increment() {
state.count++;
}
return {
state,
increment,
};
},
};
</script>
<style lang="less" scoped>
.app {
background: fade(pink, 80%);
padding: 10px;
border-radius: 5px;
margin: 10px;
}
</style>
同样的命令我们让它运行起来
yarn parcel src/index.html
对于Vue和React项目,他们的webpack配置会有很多不同,但在上面这两个例子,显然我们能深刻体会到“开箱即用”带来的收益。
PS: 如果想要同时在一个项目中跑Vue和React web app,需要使用正规的微前端框架并将Vue和React的依赖安装在两个sub package中,否则Parcel会不知道jsx是要转化成Vue还是React的jsx
图片资源
与Webpack不同,对于image,Parcel提供了更多的功能,因此写法上也有差异。 在Javascript中,需要这样引入一张图片
const imageUrl = new URL(
'image.jpeg?as=webp&width=250',
import.meta.url
);
HTML和css中则简单很多
<html>
<head>
<meta charset="utf-8" />
<title>HTML Example</title>
</head>
<body>
<picture>
<source srcset="image.jpeg?as=avif&width=800" type="image/avif" />
<source srcset="image.jpeg?as=webp&width=800" type="image/webp" />
<source srcset="image.jpeg?width=800" type="image/jpeg" />
<img src="image.jpeg?width=200" alt="test image" />
</picture>
</body>
</html>
body {
background: url('images/background.png');
}
比起url-loader带来的简单的import imageURL from 'someImage.png',new URL更加复杂,但它也带来了下列能力
- 更改图片尺寸,通过
width,height参数 - 更改图片质量,通过
quality参数,0到100之间的百分比,数值越大图片越清晰,数值越小图片体积越小 - 转换图片类型,通过
as参数,可以将图片转化为webp,jpeg/jpg,png,avif
React SVGR
对于SVG图片它的引入方式与一般图片相同。但如果你是React框架的使用者,那么SVGR也许更适合。它能将引入的svg资源自动转化成React组件。 此处,我们需要进行一些微量的配置
yarn add -D @parcel/transformer-svg-react
在项目根目录下创建一个.parcelrc文件
{
"extends": "@parcel/config-default",
"transformers": {
"*.svg": ["...", "@parcel/transformer-svg-react"]
}
}
然后就可以将svg作为React组件引入
import AddIcon from "./AddIcon.svg";
export function AddButton() {
return (
<button aria-label="Add">
<AddIcon />
</button>
);
}
node环境变量
对于web app来说,它的执行环境中是不存在process.env的。我们能在我们的代码中使用process.env.NODE_ENV等环境变量,是在编译时被替换成编译环境下的环境变量。Webpack使用EnvironmentPlugin来进行环境变量的替换。
但对于Parcel来说,我们只要直接读取process.env中的字段,Parcel检测到相关代码后便会自动从当前编译时环境变量中取值并替换。下列两种方法都是可以的。
console.log(process.env.API_KEY);
const { API_KEY } = process.env;
除此之外,当我们需要批量设置环境变量时,Parcel支持.env,.env.production,.env.development 等环境变量配置文件,当Parcel进入构建时,会自动将.env*中的环境变量配置加载到node执行上下文中。
.env文件中支持NAME=value这样的键值对。下面便是一个例子
APP_NAME=test
API_KEY=12345
如果NODE_ENV="production",那么.env.development和.nev.development.local将不会被用到,在NODE_ENV="development"中同理
他们的优先级为.env.local > .env.production.local > .env.production > .env
构建
同样构建命令与watch命令大同小异
yarn parcel build src/index.html
最终的构建产物便会在dist目录下。如果需要输出到其它地方,请使用--dist-dir 参数
另外,在生产环境中,我们构建出的图片,js脚本等静态资源并不会和HTML文件存放于同一处而是在CDN上。因此我们需要将资源的路径也指向CDN上。
通过传递--public-url参数,就能指定资源在CDN上的位置
yarn parcel build src/index.html --public-url="https://cdn.ringcentral.com/glip"
总结
这些场景下,比起Webpack用Parcel更好用
- 假如项目使用Webpack,用脚手架生成Webpack的配置之后便不再更改Webpack配置,并且你不需要对 webpack dev server进行一些配置
- Demo或者快速写一个原型时
- 发布到npm上的包
- Chrome扩展插件 但目前来说,相对于Webpack,Parcel被用于构建大型项目的经验还比较少,也许在未来,当它的插件生态更加丰富的时候,便是从Webpack口中抢下更多市场的时候