关于将codepen迁移到本地的一次思考

2,811 阅读7分钟

关于将codepen迁移到本地的一次思考

这个是我将codepen上面写的五子棋迁移到本地,并用webpack打包的一些思考,大家可以去玩一玩,顺便看一看我是如何配置我的webpack,以及这个五子棋怎么写的。

大家可以一边参照github上的源代码一边看这篇文章。

github源代码

codepen在线演示(github上面的为修改后的最新版)

为什么我们要迁移到本地

用过codepen的都知道,codepen 是一个很好用的,网页demo快速编写工具。你只需要在左边编写你的网页,然后就可以在右边实时预览他的效果。例如下图:image-20201126082839120

并且他提供了许多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

image-20201126084443536

在我写这篇文章的时候,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调用相应的预处理工具,所以不仅需要安装相应的预处理工具,例如pugsasstypescript,还需要安装相应的loader,例如pug-loadersass-loaderts-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。