zhen's blog

编译思想,编译人生

基于webpack与TypeScript的SolidJS项目搭建

本文将讲述如何基于webpack与TypeScript搭建一个基础的支持less模块的solidjs项目。方便后续涉及到solidjs相关分析与讨论都可以基于本文的成果之上进行。

前置

  1. nodejs v14+
  2. 全局yarn(npm亦可)
  3. 稳定的网络环境

创建根目录solidjs-webpack-ts-example

1
2
mkdir solidjs-webpack-ts-example
cd solidjs-webpack-ts-example

yarn初始化

1
2
3
4
5
6
7
8
9
10
11
12
➜  solidjs-webpack-ts-example git:(main) yarn init                                                          
yarn init v1.22.19
question name (solidjs-webpack-ts-example):
question version (1.0.0):
question description:
question entry point (index.js):
question repository url:
question author (w4ngzhen <[email protected]>):
question license (MIT):
question private:
success Saved package.json
✨ Done in 3.68s.

git初始化

1
2
3
4
# 前置:添加.gitignore文件
git init
git add .
git commit -m "init"

库安装

webpack 4件套

1
yarn add -D webpack webpack-cli webpack-dev-server html-webpack-plugin

样式处理 4件套

1
yarn add -D less less-loader css-loader mini-css-extract-plugin
  1. less:less核心编译解析库;

  2. less-loader:webpack与less的桥梁。当webpack处理less时,通过配置指定交给less-loader,less-loader调用安装的less,将less代码编译为css代码;

  3. css-loader:wepback处理css样式代码的loader。处理css,或处理来自less编译成的css;

  4. mini-css-extract-plugin:css样式处理最后一个环节,交给该插件的提供的loader、plugin完成独立样式文件打包生成。

babel 7件套

1
2
3
4
yarn add -D @babel/core
yarn add -D @babel/preset-env @babel/preset-typescript babel-preset-solid
yarn add -D @babel/plugin-proposal-class-properties @babel/plugin-proposal-object-rest-spread
yarn add -D babel-loader
  1. @babel/core:babel核心库;
  2. @babel/preset-env、@babel/preset-typescript、babel-preset-solid(这个preset名字目前没有符合babel规范):babel扩展preset,整合当前主流浏览器支持语法、typescript语法支持以及solidjs相关语法支持;
  3. @babel/plugin-proposal-class-properties、@babel/plugin-proposal-object-rest-spread:babel扩展插件,支持类定义属性以及...剩余属性解构语法;
  4. babel-loader:webpack与babel的桥梁。当webpack处理相关代码的时候,通过配置指定交给babel-loader,babel-loader内部调用上述第1个babel核心库,并结合相关的preset、plugin完成代码编译。

TypeScript 1件套

实际山,主流IDE(WebStorm、VSCode)等都内置了TypeScript库,可以不用安装TS,只需要配置tsconfig.json就可以完成代码编写过程中的类型检查(babel编译的时候,不会进行类型检查)。关于这一块,推荐大家阅读另一篇文章:【长文详解】TypeScript与Babel、webpack的关系以及IDE对TS的类型检查 - 知乎 (zhihu.com)

为了方便的进行类型检查,本样会安装项目级:

1
yarn add -D typescript

至此,我们安装了目前基础项目所需要的开发依赖(devDependencies)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
"name": "solidjs-webpack-ts-example",
"version": "1.0.0",
"main": "index.js",
"author": "w4ngzhen",
"license": "MIT",
"devDependencies": {
"@babel/core": "^7.21.3",
"@babel/plugin-proposal-class-properties": "^7.18.6",
"@babel/plugin-proposal-object-rest-spread": "^7.20.7",
"@babel/preset-env": "^7.20.2",
"@babel/preset-typescript": "^7.21.0",
"babel-loader": "^9.1.2",
"babel-preset-solid": "^1.6.13",
"css-loader": "^6.7.3",
"html-webpack-plugin": "^5.5.0",
"less": "^4.1.3",
"less-loader": "^11.1.0",
"mini-css-extract-plugin": "^2.7.5",
"typescript": "^5.0.2",
"webpack": "^5.76.2",
"webpack-cli": "^5.0.1",
"webpack-dev-server": "^4.13.1"
}
}

SolidJS 2件套

1
yarn add solid-js @solidjs/router
  1. solid-js:SolidJs核心库;
  2. @solidjs/router:solidjs官方SPA路由组件。

项目配置

tsconfig.json

项目根目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"noEmit": true,
"skipLibCheck": true,
"jsx": "preserve",
"jsxImportSource": "solid-js"
},
"include": [
"src"
]
}

webpack.config.js

项目根目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
const {resolve} = require('path');
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
mode: "development",
entry: {
main: resolve(__dirname, 'src', 'index.tsx')
},
output: {
filename: "app.js",
path: resolve(__dirname, 'dist')
},
resolve: {
// webpack 默认只处理js、jsx等js代码
// 为了防止在import其他ts代码的时候,出现
// " Can't resolve 'xxx' "的错误,需要特别配置
extensions: ['.js', '.jsx', '.ts', '.tsx']
},
module: {
rules: [
{
test: /\.tsx?/,
use: [
'babel-loader'
],
exclude: /node_moudles/
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader'
]
},
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader'
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: resolve(__dirname, 'public', 'index.html'),
inject: 'body',
favicon: resolve(__dirname, 'public', 'favicon-32x32.png')
}),
new MiniCssExtractPlugin({
filename: 'app.css'
})
],
devServer: {
port: 8080
}
}

.babelrc

项目根目录

1
2
3
4
5
6
7
8
9
10
11
{
"presets": [
"@babel/preset-env",
"@babel/preset-typescript",
"babel-preset-solid"
],
"plugins": [
"@babel/plugin-proposal-object-rest-spread",
"@babel/plugin-proposal-class-properties"
]
}

package.json

添加开发、构建以及类型检查脚本:

1
2
3
4
5
6
7
8
9
{
... ...
+ "scripts": {
+ "typecheck": "tsc",
+ "start": "webpack-dev-server --config webpack.config.js",
+ "build": "webpack --config webpack.config.js --mode=production"
+ },
... ...
}

初始文件创建

app.d.ts

路径:项目根目录/src/app.d.ts。涉及到譬如less模块在ts中使用的类型定义。

1
2
3
4
5
6
declare module '*.module.less' {
const content: {
[className: string]: any
}
export default content;
}

index.html

路径:项目根目录/public/index.html(主要是与webpack中的HtmlWebpackPlugin.template选项对应)。

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<title>SolidJS webpack ts example</title>
</head>
<body>
<div id="app"></div>
</body>
</html>

PS:public目录还创建了一个icon,就不详细说明了。

index.tsx

路径:项目根目录/src/index.tsc

1
2
3
4
5
6
7
8
9
10
11
12
import {render} from 'solid-js/web';
import styles from './index.module.less';

function HelloWorld() {
return (
<div class={styles.hello}>
<p>Hello World!</p>
</div>
);
}

render(() => <HelloWorld/>, document.querySelector('#app')!)

index.module.less

路径:项目根目录/src/index.module.less

1
2
3
4
5
6
.hello {
p {
font-size: 16px;
color: #2c4f7c;
}
}

项目运行效果

010-example-show

附录

项目代码地址:

w4ngzhen/solidjs-webpack-ts-example (github.com)