关于将codepen迁移到本地的一次思考
这个是我将codepen上面写的五子棋迁移到本地,并用webpack打包的一些思考,大家可以去玩一玩,顺便看一看我是如何配置我的webpack,以及这个五子棋怎么写的。
大家可以一边参照github上的源代码一边看这篇文章。
为什么我们要迁移到本地
用过codepen的都知道,codepen 是一个很好用的,网页demo快速编写工具。你只需要在左边编写你的网页,然后就可以在右边实时预览他的效果。例如下图:
并且他提供了许多HTML、CSS、HTML预处理工具。例如HTML有pug,ejs等等;CSS有scss,sass,less等;Javascript有Babel、Typescript、coffeescript等等。使用它我们的确可以在网页中快速的完成我们的demo开发,但是如果codepen不能满足你的一些需求了呢?在codepen中,没有代码智能提示,也没有一个快速的代码格式化工具,并且如果出错了的话,错误提示也是形同虚设。此时,可能就需要我们在本地搭建一个项目,将我们的demo转移到本地继续开发。
迁移方案思考
如果你在codepen中知识简简单单的使用HTML、CSS、Javascript写点小demo,此时本地的项目搭建十分简单,你只需要新建一个文件夹,然后把codepen的html等文本内容复制下来然后粘贴保存,然后修改一下链接情况即可。但是如果你使用了类似于pug、scss、typescript等编译工具呢?你可能会想,那我新起一个npm项目,然后把pug、scss、typescript分别编译成html等文件,再在html中将他们链接上不就好了吗?这样的做法看上去可行,但是实际上操作下来会发现十分低效。因为每次修改了文件,都需要自己去手动编译一遍,然后才能在浏览器里面看到效果,这个和codepen的体验相差甚远。那你可能会想,这个时候我们的需求就是修改文件之后自动编译就可以了,那我们可以使用nodemon来对源文件进行监视,每次操作之后再分别进行编译就可以了。这样理论上是没有问题的,但是只能适用于初学者的摸索阶段。实际工程中,源文件是十分庞大的,每次修改一小部分都需要进行全量编译,等待的时间实在是遭不住。
正确方式
实际上关于前端资源打包,已经有了一个成熟的方案,那就是webpack。
本质上,webpack 是一个用于现代 JavaScript 应用程序的静态模块打包工具。当 webpack 处理应用程序时,它会在内部构建一个 依赖图(dependency graph),此依赖图对应映射到项目所需的每个模块,并生成一个或多个 bundle。
在我写这篇文章的时候,webpack已经为5.6.0版本了,下面的内容也是基于5.6.0版本的。
webpack自webpack4以来,就可以无需配置快速上手,这无异是大大减少了freshman的上手难度。如上图所示,webpack会将所有的奇奇怪怪的依赖,编译成浏览器看得懂,能直接运行的文件。但其实并不是webpack编译上图左边的文件,然后用一种魔法的方式将他们结合在了一起,而是webpack的loader起了作用。
loader
loader 用于对模块的源代码进行转换。loader 可以使你在
import
或 "load(加载)" 模块时预处理文件。因此,loader 类似于其他构建工具中“任务(task)”,并提供了处理前端构建步骤的得力方式。loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript 或将内联图像转换为 data URL。loader 甚至允许你直接在 JavaScript 模块中import
CSS文件!
webpack通过loader与相应的预处理工具链接,例如你需要处理pug、scss、ts文件,因为webpack并不提供编译上面文件的能力,而是通过loader调用相应的预处理工具,所以不仅需要安装相应的预处理工具,例如pug
、sass
,typescript
,还需要安装相应的loader,例如pug-loader
,sass-loader
,ts-loader
。
module: {
rules: [
{
test: /\.pug$/,
include: path.resolve(__dirname, 'src'),
use: 'pug-loader'
},
{
test: /\.ts$/,
include: path.resolve(__dirname, 'src'),
use: "ts-loader"
},
{
test: /\.scss$/i,
include: path.resolve(__dirname, 'src'),
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"sass-loader"
]
}
]
}
plugin
插件是 webpack 的 支柱 功能。webpack 自身也是构建于你在 webpack 配置中用到的相同的插件系统之上!
插件目的在于解决 loader 无法实现的其他事。
loader提供了与预处理软件结合的能力,而通过插件,我们可以做到一些无法实现的事。例如webpack默认是把css一起打包到js文件里面的,但是如果你想把css单独提出来,放在html的head里面,把js放到body下面。那这个时候我们就需要借助MiniCssExtractPlugin
的能力;又或者我们需要每次构建都清除dist
目录,我们需要借助CleanWebpackPlugin
的能力等等。
plugins: [
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: "[name].[contenthash].css"
}),
new HtmlWebpackPlugin({
template: "./src/index.pug",
inject: true
})
]
配置 vs 无配置
全部的配置大家去github上看吧,就不粘贴过来占篇幅了。
我最新提交的代码中,已经将开发模式与生产模式拆分为两个不同的配置文件,其中相同的部分放在
webpack.common.js
中,大家直接参照这个文件就可以了。
在上文我们说过,webpack无需配置即可运行,但并不意味着我们完全不需要配置它。灵活性与配置简单总是不可兼得的。如果我们的webpack不是通过配置文件来声明我们需要使用什么loader、什么plugin,而是通过嗅探package.json文件,然后自己按照默认的配置进行加载,我们用的时候无异是提心吊胆的。那我们接下来就配置一下我们的webpack吧。
webpack默认以webpack.config.js
作为配置的入口点,当然你也可以使用-c
选项来显式的声明我们需要使用的配置文件。例如我们需要将开发模式与生产模式分离开,那就需要加载不同的配置。
大功告成后的思考
那进行了上面的配置,我们已经拥有了一个可以直接把codepen里面的内容复制过来,然后可以直接运行的环境了。但如果下次我们CSS预处理器使用的不是scss,而是less;HTML模版我们使用的不是pug,而是ejs了怎么办呢?那我们还是新建一个webpack项目,然后去安装不同的loader,写不同的配置文件吗?或者是把以前的配置文件复制过来,然后再改一改呢?这无异有一点坏味道的感觉。
规范
我还没有实现哈哈哈,只是有了这个思路,等我实现了再写一篇文章。
与其这样没有规范的、繁琐的生成一个项目,不如将里面相同的部分抽象出来。构建一个属于自己团队的CLI,然后每次生成项目的时候通过引导生成对应的项目。写到这里大家也就明白了,我们之所以需要基建,并不是KPI为导向,而是这样的设计可以更规范,更简单的更快速的达到一个目的,可以简化我们的工作。
总结
如果你学习遇到了瓶颈,觉得自己只会调用库,用现有的工具开发网页,不如试着去深入的思考一下,怎么才能减少这些不必要的重复操作,让前端更自动化,更lowcode。