前端模块化开发实验(二)—— 纯JS 模块的Welcome world
当我们往/src 目录创建新源文件,或拷入新资源数据(例如图片),它们都均属于某一种类型 「web模块」。类型 的意义是说,它是有某种 固定格式,包括外部形式,和内部构成。例如 V模块类型一定会访问DOM的,样式模块一定有样式定义,并提供给V模块使用等等。本文我们正式开始写V模块。
上一篇我们 为前端模块化开发 做了最基础的工作,包括webpack基础配置(包括开发服务器),和index模块的创建,还创建了一测试的V模块app.js。
然而,这些基础配置是不完整的。第一,app.js没有被转译为更通用的 ES5代码;第二,没有配置支持开发CSS和资源模块。本文任务就是配置更完整的 webpack,并且开发更完整功能 Welcome world 作演示。
Welcome world UI结构
index L app L Layout L css E Greeting L css, png
源文件格式
在开始配置 webpack 之前,我们先弄清一些关于 源文件格式的概念。有webpack使用经验的知道,我们既可以用ES6写V模块,也可以用Typescript写,也可用 JSX;同样,我们可以直接写 CSS,也可以用SASS。只要我们作相应的配置,我们可以使用不同的源文件格式写web模块。但是,webpack 目标是打包符合标准的 能在大多数浏览器上运行的代码,所以编写的源文件格式不对时(例如浏览器不能运行TS),要先转译,这就是 loader(https://webpack.js.org/loaders/) 的任务——打包前先进行格式转换。
本文选择 使用 ES6 格式编写 V模块,CSS 写 样式模块(不用SASS),和直接使用图片格式 作 资源模块。注意,这里CSS不用转译 还是需要配置loader,而且还是两个,显然 loader的任务 没有固定标准,因模块类型而有不同。
好,理论到处为止,开始动手。
Babel 和 ES6格式模块
要转译打包 ES6格式源文件,我们需要安装 babel-loader 和 babel 本身,babel要安装包括 核心(@babel/core )和 基本预设(@babel/preset-env ):
$ npm i -D babel-loader @babel/core @babel/preset-env
配置 webpack.config.js
module: {
rules: [
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
]
}
css-loader 和 原始CSS格式模块
样式开发有很多技术,例如有 CSS-in-JS,有CSS preprocessor,有PostCSS,每种需要特定的 loader转译,本文暂时都不用。为了支持样式模块开发,至少安装两个webpack loader:
- css-loader - 解释 CSS imports,生成依赖图
- style-loader - 将样式定义注入 DOM
$ npm i -D css-loader style-loader
配置 webpack.config.js
注意loader加载顺序,先解释,再注入,倒序加载:
module.exports = {
/* ... */
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
}, ],
},
}
layout V模块
好了,现在我们开始编写 V模块 ,测试这些webpack配置。从上面草图中,我们看到了两个V模块的大概内容和关系,先分析 layout V:
- 第一,它是个典型的“哑UI”,没有交互状态,就是一个布局容器;
- 第二,它和 greeting V有嵌套调用关系;greeting 是它的子V;
- 第三,它有一个 内容垂直和水平居中的样式定义,为了演示样式模块,将定义独立成layout.css;
- 第四,app模块 加载 layout模块;
layout.css
.centerbox {
/*https://coryrylan.com/blog/how-to-center-in-css-with-flexbox*/
height:100vh;
display: flex;
justify-content: center;
color: green;
align-items: center;
}
.greeting{
display: inline-block;
}
greeting.js
// Create Greeting node
const Greeting = document.createElement('h1');
Greeting.textContent = 'Hello Web World!';
const box = document.createElement('div');
box.classList = "greeting";
box.append(Greeting)
export default box;
layout.js
import './layout.css';
import Greeting from './greeting.js';
const Container = document.createElement('div');
Container.classList = "centerbox";
Container.append(Greeting);
export default Container;
greeting V 模块
布局V 引入一个水平和垂直居中的样式模块,接着开发 Greeting这个V模块。
为了演示 V模块类型的丰富性,Greeting V 有图片,和简单的用户交互(状态交互会在下一文中演示)。为了支持 图片资源模块,要先配置webpack。
webpack 5之后 对 资源模块有内置支持,不需要像4时需要安装额外loader了:
module.exports = {
/* ... */
module: {
rules: [
// Images
{
test: /\.(?:ico|gif|png|jpg|jpeg)$/i,
type: 'asset/resource',
}, ],
},
}
然后我们 “制作”(拷贝)一个图片模块在 ./images/webpack.gif
// Create Greeting node
import webpack\_logo from './images/webpack.gif'
const Logo = document.createElement('img');
Logo.src = webpack\_logo;
const Greeting = document.createElement('h1');
Greeting.textContent = 'Hello Web World!';
const box = document.createElement('div');
box.classList = "greeting";
box.append(Logo);
box.append(Greeting);
export default box;
再增加一个交互输入:
...
//////// 3 User Input /////////
const userInput = document.createElement('input');
//////// 4 Submit Button /////////
const btn = document.createElement('button');
btn.innerText = "click me";
btn.onclick = hello;
/////// 5 submit event handler ////////
function hello(e){
if(userInput.value.trim() == "") return alert("What's you name?");
let name = userInput.value;
Greeting.textContent = \`Hello,${name} Welcome Web world!\`;
console.log(e);
return;
}
....
小结
Greeting 这个V 模块 是本实验的核心,然而作为一个V,它几乎没有什么功能,代码居然已经有40多行。因为每个UI元素都要手动创建,设置,绑定事件等等。这也是早期web前端编程的样子了。后来的一代MVC框架,可以引jquery和 template技术 简单化 V模块开发。不过,本系列不计划介绍像Backbone这样的框架,直接使用 React 和Vue 改造。
源码
这里(https://github.com/nakeman/modular-web-frontend-webpack-js),在tag v0.2上。