聊一聊前端工程化演进的那些事

408次阅读  |  发布于2年以前

背景

前端工程化的演进不是独立的,是和前端其他领域息息相关,一起成长起来的,下面将从几个维度先介绍一下前端发展背景。

前端职业演进

ES演进

开发模式

前端工程化

石器时代(JSP/PHP/单文件模式)

对前端的需求较弱,页面比较简单,开发过程中没有太多辅助工具 ,须臾手动预览文件、刷新代码,前端代码「装饰」在PHP等代码中。

(时代过于久远,这里贴一张图给大家体验一下)

青铜时代(非JS技术栈的打包工具)

maven介绍

托管公司内部的maven jar/aar包,为客户端或其他java程序发布提供支持。Maven 是一个构建自动化工具,主要用于 Java 项目。Maven 还可用于构建和管理用 C#、Ruby、Scala 和其他语言编写的项目。Maven 项目由 Apache 软件基金会托管,它以前是雅加达项目的一部分。

YUI Compressor

YUI Compressor是当时业界巨头yahoo提供的一个前端压缩工具,除了Compressor,雅虎当时还提供了很多前端相关的工具和组件库。

https://yui.github.io/yuicompressor/

一个maven打包js的小例子

        <plugins>
            <plugin>
                <!-- YUI Compressor Maven压缩插件 -->
                <groupId>net.alchim31.maven</groupId>
                <artifactId>yuicompressor-maven-plugin</artifactId>
                <version>1.5.1</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>compress</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <!-- 读取js,css文件采用UTF-8编码 -->
                    <encoding>UTF-8</encoding>
                    <!-- 不显示js可能的错误 -->
                    <jswarn>false</jswarn>
                    <!-- 若存在已压缩的文件,会先对比源文件是否有改动  有改动便压缩,无改动就不压缩 -->
                    <force>false</force>
                    <!-- 在指定的列号后插入新行 -->
                    <linebreakpos>-1</linebreakpos>
                    <!-- 压缩之前先执行聚合文件操作 -->
                    <preProcessAggregates>true</preProcessAggregates>
                    <!-- 压缩后保存文件后缀 无后缀 -->
                    <nosuffix>true</nosuffix>
                    <!-- 源目录,即需压缩的根目录 -->
                    <sourceDirectory>src/main/static</sourceDirectory>
                    <!-- 输出目录,即压缩后的目录-->
                    <outputDirectory>target/classes</outputDirectory>
                    <force>true</force>
                    <!-- 压缩js和css文件 -->
                    <includes>
                        <include>**/*.js</include>
                        <include>**/*.css</include>
                    </includes>
                    <!-- 以下目录和文件不会被压缩 -->
                    <excludes>
                        <exclude>**/*.min.js</exclude>
                        <exclude>**/*.min.css</exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>

总结

前端代码会作为后端工程的一部分,被maven类的工具统一管理,发布到对应的后端工程中

打包过程中js、css只能做简单的打包压缩,无法做进一步的管理。

白银时代(JS技术栈打包工具)

通过编写bash或nodejs编写任务脚本,实现命令式的热更新(HMR)和自动打包,代表:Grunt、Gulp;

Grunt介绍

参考官网:https://www.gruntjs.net/getting-started

一个Grunt打包的小例子

module.exports = function (grunt) {
    // Project configuration.
    grunt.initConfig({
        pkg: grunt.file.readJSON( package.json ),
        uglify: {
            options: {
                banner: '/*! <%= pkg.name %> <%= grunt.template.today( yyyy-mm-dd ) %> */\n',
            },
            build: {
                src:  build/index.js ,
                dest:  build/<%= pkg.name %>.min.js ,
            },
        },
        concat: {
             build/index.js : [ src/foo.js ,  src/bar.js ],
        },
    });

    // 加载包含  uglify  任务的插件。
    grunt.loadNpmTasks( grunt-contrib-uglify );

    // 加载包含  concat  任务的插件。
    grunt.loadNpmTasks( grunt-contrib-concat );

    // 默认被执行的任务列表。
    grunt.registerTask( default , [ concat ,  uglify ]);
};

总结

JS技术栈的打包工具,前端可以基于node实现自己的打包工具,功能点和非js技术栈类似。

黄金时代(Bundle)

基于Bundle的概念,借用babel的能力,让js文件按模块的方式进行打包,实现了HMR、以及各类处理器,让前端的工程化脱离了简单的压缩合并,转入了更加丰富的黄金时间,代表:Webpack、Rollup;

一个webpack的小例子

var webpack = require('webpack');var path = require('path');var HtmlWebpackPlugin = require('html-webpack-plugin')var CleanWebpackPlugin = require('clean-webpack-plugin')var ExtractTextPlugin = require('extract-text-webpack-plugin')var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')const VENOR = [ faker ,
   lodash ,
   react ,
   react-dom ,
   react-input-range ,
   react-redux ,
   redux ,
   redux-form ,
   redux-thunk ,
   react-router ]module.exports = {
  entry: {
    bundle: './src/index.js',
    vendor: VENOR
  },
  // 如果想修改 webpack-dev-server 配置,在这个对象里面修改
  devServer: {
    port: 8081
  },
  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].[chunkhash].js'
  },
  module: {
    rules: [{
        test: /.js$/,
        use: 'babel-loader'
      },
      {
        test: /.(png|jpe?g|gif|svg)(?.*)?$/,
        use: [{
            loader: 'url-loader',
            options: {
                limit: 10000,
                name: 'images/[name].[hash:7].[ext]'
            }
        }]
    },
    {
        test: /.css$/,
        loader: ExtractTextPlugin.extract({
            fallback: 'style-loader',
            use: [{
            // 这边其实还可以使用 postcss 先处理下 CSS 代码
                loader: 'css-loader'
            }]
        })
    },
    ]
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: ['vendor', 'manifest'],
      minChunks: Infinity
    }),
    new CleanWebpackPlugin(['dist/*.js'], {
      verbose: true,
      dry: false
    }),
    new HtmlWebpackPlugin({
      template: 'index.html'
    }),
    // 生成全局变量
    new webpack.DefinePlugin({
       process.env.NODE_ENV : JSON.stringify( process.env.NODE_ENV )
    }),
    // 分离 CSS 代码
    new ExtractTextPlugin( css/[name].[contenthash].css ),
    // 压缩提取出的 CSS,并解决ExtractTextPlugin分离出的 JS 重复问题
    new OptimizeCSSPlugin({
      cssProcessorOptions: {
        safe: true
      }
    }),
    // 压缩 JS 代码
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    })
  ]};

总结

正如webpack官网的banner图描述,这个节点前端构建脱离了简单的文件拼接压缩,真正触摸到了js间的关联,提供了更科学的工程化方案。

后黄金时代(Bundleless)

在Bundle的基础上,结合浏览器解析原生ESM模块的特性,实现Bundleless的开发预览及热更新(HMR),直接不打包发布或采用webpack等集成式工具兼容打包,代表:esbuild、snowpack。

snowpack介绍

官网介绍(from https://www.snowpack.dev/):

Snowpack is a lightning-fast frontend build tool, designed for the modern web. It is an alternative to heavier, more complex bundlers like webpack or Parcel in your development workflow. Snowpack leverages JavaScript's native module system (known as ESM) to avoid unnecessary work and stay fast no matter how big your project grows.

一个snowpack的小例子

/** @type {import( snowpack ).SnowpackUserConfig } */
export default {
  mount: {
    public: { url: '/', static: true },
    src: { url: '/dist' },
  },
  plugins: [
    '@snowpack/plugin-react-refresh',
    '@snowpack/plugin-dotenv',
    [
      '@snowpack/plugin-typescript',
      {
        /* Yarn PnP workaround: see https://www.npmjs.com/package/@snowpack/plugin-typescript */
        ...(process.versions.pnp ? { tsc: 'yarn pnpify tsc' } : {}),
      },
    ],
  ],
  routes: [
    /* Enable an SPA Fallback in development: */
    // { match :  routes ,  src :  .* ,  dest :  /index.html },
  ],
  optimize: {
    /* Example: Bundle your final build: */
    //  bundle : true,
  },
  packageOptions: {
    /* ... */
  },
  devOptions: {
    /* ... */
  },
  buildOptions: {
    /* ... */
  },
};

总结

思路上和webpack接近,解决了很多webpack的痛点,但是概念是没有grunt->webpack那么突破,所以定义为后黄金时代。

未来

前端工程化的未来有很多方向,有致力于提供全新工程化体系的Modern.js(https://modernjs.dev/),也有从效率出发,希望实现更自动、更智能的流水线方向的,不过结合其他语言的工程化进程,如 Java(https://blog.csdn.net/nalw2012/article/details/92802062),工程化的演进可能还需要依赖整个生态的演进才能有更革命性的进展。

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8