工程启动和webpack的几个问题与解答

1,818 阅读6分钟

最近在研究微服务,主要是single SPA框架。Single SPA的微服务理念,根据我的理解是这样:

  • 首先创建一个主项目,主项目的工作是完成一些通用的工作,比如消息总线等
  • 按需要创建或者改造n个子项目,打包成umd模块
  • 在主项目中按照路由汇总所有子项目的入口信息,比如
{
          name: "react app",
          entry: "//localhost:8100",
          render,
          activeRule: genActiveRule("/react")
      }
  • 从主项目的index.html或者index.js启动整个app
  • 当用户打开某个子页面比如/subproject1时,根据主项目中配置的subproject1的入口文件,按需加载js或者html,渲染页面,显示内容

这个中间遇到了很多webpack相关的问题:

  • 启动一个app的方式有很多种,npm run dev, npm start, parcel index.html,node index.js, webpack-dev-server index.js etc, 它们分别在做什么
  • 当我启动一个项目的时候,我什么时候使用的是/build下的文件,什么时候用的是开发环境的文件?
  • webpack打包的文件中有一个main.js 和很多个code splitting后的chunk文件,这个main文件是怎么和那些chunk文件联系到一起的?
  • code splitting的原理是什么?微服务中如何引用code splitting的项目

针对每个问题,开始寻找答案

启动一个app的方式有很多种,npm run dev, npm start, parcel index.html,node index.js, webpack-dev-server index.js etc, 它们分别在做什么 ==>汇总为问题1 到底有多少种启动app的方式,区别是什么

1. npm start/ npm run start / node *.js

npm start == npm run start = node server.js

//node.js有两个特殊脚本任务  start  test,执行这两个任务可以简写的方式
npm run start  == npm start //# 执行"start"指定的脚本
npm run test == npm test 

//其他任务不可省略,务必以 npm run 方式执行
npm run dev     //开发环境启动vue
npm run build     //打包生产环境需要文件

所以很多时候package.json 文件中不需要写start的脚本,下面这个start就是多余的

"scripts": {
    "start": "node server.js",
    }

npm start是如何启动一个app的呢? 也就是node server.js是怎么启动一个app的,去观察一个app,会发现每个app里都有个server.js,这个文件跟页面布局这些东西都无关,会引入express,然后通过express启动一个端口,并且挂载/buid文件夹

// 初始化一个express实例
const app = express();

//设置文件目录
setup(app, {
  outputPath: resolve(process.cwd(), 'build'), //process是nodejs的全局变量,process.cwd()返回当前目录
  publicPath: '/'
});

// 启动app,设置端口port
app.listen(port, host, (err) => {
  if (err) {
    return logger.error(err.message);
  }
  logger.appStarted(port, prettyHost);
});

Express的核心源码就是接收request 返回response

interface Express extends Application {
    request: Request;
    response: Response;

即使没有webpack,也可以这样跑起来一个app

2. 利用webpack启动一个app

使用webpack的理由千千万,就不说了。 一个项目如何启用webpack呢?

  • 安装webpack 依赖
npm install webpack webpack-cli webpack-dev-server
  • package.json 文件中添加脚本启用webpack
"scripts": {
    "build": "webpack"
    }
  • 执行npm run build即可

webpack命令会启动complier,根据config文件中配置的loader等打包项目文件,输出到指定的文件夹(原理

启动工程跑在浏览器的话使用 webpack-dev-server 工具,本身webpack-dev-server启动了一个使用express的http服务器,这个服务器与客户端采用websocket通信协议,当原始文件发生改变,webpack-dev-server会实时编译

1.webpack-dev-server伺服的是资源文件,不会对index.html的修改做出反应

2.webpack-dev-server生成的文件在内存中,因此不会呈现于目录中,生成路径由content-base指定,不会输出到output目录中。

3.默认情况下: webpack-dev-server会在content-base路径下寻找index.html作为首页

4.webpack-dev-server不是一个插件,而是一个web服务器,所以不要想当然地将其引入

3. 利用nodemon启动一个app

nodemon用来监视node.js应用程序中的任何更改并自动重启服务,非常适合用在开发环境中。nodemon将监视启动目录中的文件,如果有任何文件更改,nodemon将自动重新启动node应用程序。 nodemon是node的一个替换,所以nodemon如何启动一个app只要看node如何启动一个app,回到上面node server.js 的工作原理上

结合nodemon的使用,我也启动脚本变成

 "dev": "node ./node_modules/nodemon/bin/nodemon.js",

nodemon.js 会自动寻找nodemon.json 配置文件

{
  "ignore": ["**/*.test.js", "**/*.spec.js", ".git", "node_modules"],
  "watch": ["server", "config"],
  "exec": "npm start",
  "ext": "js"
}

相当于监听了npm start的命令,项目发生改变时,重跑npm start

    "start": "cross-env NODE_ENV=development ENV=development node server",

回到node server启动项目

总结 以上的npm 启动node server都是启用了node中的httpclient。 还有一些常用的容器比如nginx, tomcat可以挂载app

当我启动一个项目的时候,我什么时候使用的是/build下的文件,什么时候用的是开发环境的文件?

npm start是开发模式,使用的是开发文件。 npm run build会把代码编译到build 目录,webpack做过了压缩和优化 要想挂载/build下的文件,可以在本地使用静态服务器,也可以部署到tomcat 等容器中

静态服务器

npm install -g serve
serve -s build

,build好的东西放在服务器tomcat中webapp下的Root中,开启8080就可以看到项目内容

webpack打包的文件中有一个main.js 和很多个code splitting后的chunk文件,这个main文件是怎么和很多chunk文件联系到一起的?

Webpack提供文件分离的功能,包含两个部分: Bundle Splitting 和 Code splitting

  • Bundle splitting: 创建更多更小的文件,并行加载,以获得更好的缓存效果,主要作用就是使浏览器并行下载,提高下载速度。并且运用浏览器缓存,只有代码被修改,文件名中的哈希值改变了才会去再次加载。
  • Code splitting: 只加载用户最需要的部分,其余的代码都遵从懒加载的策略,主要的作用就是加快页面的加载速度,不加载不必要的代码。

main.js 是执行入口文件,*.chunk.js 是异步加载文件 打开一个页面时,通常只有主页面的内容被展示,根据设置的code splitting的策略的不同,打开一个弹窗,可能就会load进一个chunk文件,或者多个,这个饮用应该是通过相对路径引入的

code splitting的原理是什么?微服务中如何引用code splitting的项目

原理就是把需要打包在一起的代码放在一个块里,解耦没有关联的代码,这样可以有效避免只改一行代码,整个工程都要重新编译的问题。

代码拆分应该对微服务没有什么影响,有待求证