Home Web Front-end JS Tutorial Detailed analysis of Parcel source code (with examples)

Detailed analysis of Parcel source code (with examples)

Mar 18, 2019 am 10:41 AM
javascript front end Source code

This article brings you a detailed analysis of the Parcel source code (with examples). It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.

This article is an analysis of the source code of Parce, the basic code structure and execution process. If you are not familiar with parcel before, you can first go to the Parcel official website to learn more

Introduction

The following is an introduction lazily copied from the official website:

Extremely fast zero-configuration Web application packaging tool, extremely fast packaging

Parcel uses the worker process to enable multi-core compilation. There is also a file system cache to enable fast recompiling even after restarting the build.

Package all your resources

Parcel has out-of-the-box support for JS, CSS, HTML, files and more, and no plugins are required.

Automatic conversion

If necessary, Babel, PostCSS, and PostHTML and even the node_modules package will be used to automatically convert the code.

Zero-configuration code splitting

Using dynamic import() syntax, Parcel splits your output file bundles (bundles), so you only need to load the code you need on the initial load.

Hot Module Replacement

Parcel does not need to be configured. In the development environment, the module will be automatically updated in the browser as your code changes.

Friendly error log

When an error is encountered, Parcel will output a code snippet with syntax highlighting to help you locate the problem.

##browserify22.98 swebpack20.71sparcel9.98sparcel - with cache2.64s

Packaging tools

The general functions of our commonly used packaging tools:

Modularization (code splitting, merging, Tree-Shaking, etc.) Compilation (es6, 7, 8 sass typescript, etc. ) Compression (js, css, html including image compression) HMR (hot replacement)

version

parcel-bundler Version:

"version": "1.11.0 "

File structure

|-- assets          资源目录 继承自 Asset.js
|-- builtins        用于最终构建
|-- packagers       打包
|-- scope-hoisting  作用域提升 Tree-Shake
|-- transforms      转换代码为 AST
|-- utils           工具
|-- visitors        遍历 js AST树 收集依赖等

|-- Asset.js          资源
|-- Bundle.js         用于构建 bundle 树
|-- Bundler.js        主目录  
|-- FSCache.js        缓存
|-- HMRServer.js      HMR服务器提供 WebSocket
|-- Parser.js         根据文件扩展名获取对应 Asset
|-- Pipeline.js       多线程执行方法
|-- Resolver.js       解析模块路径
|-- Server.js         静态资源服务器
|-- SourceMap.js      SourceMap
|-- cli.js            cli入口 解析命令行参数
|-- worker.js         多线程入口
Copy after login

Process

Description

Parcel is resource-oriented, JavaScript, CSS, HTML are all Resources are not first-class citizens in webpack. Parcel will automatically analyze the dependencies in these files and modules starting from the entry file, then build a bundle tree, package it and output it to the specified directory

A simple example

We start with a simple example to understand the internal source code and process of parcel

index.html
  |-- index.js
    |-- module1.js
    |-- module2.js
Copy after login

The above is the structure of our example, the entrance is index.html, in index.html we use The script tag refers to src/index.js. In index.js we introduce 2 sub-modules

execution

npx parcel index.html or ./node_modules/.bin/parcel index. html, or use npm script

cli

"bin": {
    "parcel": "bin/cli.js"
}
Copy after login

to view package.json of parcel-bundler to find bin/cli.js, and point to ../src/cli## in cli.js #

const program = require('commander');

program
  .command('serve [input...]') // watch build
  ...
  .action(bundle);

program.parse(process.argv);

async function bundle(main, command) {
  const Bundler = require('./Bundler');

  const bundler = new Bundler(main, command);

  if (command.name() === 'serve' && command.target === 'browser') {
    const server = await bundler.serve();

    if (server && command.open) {...启动自动打开浏览器}
  } else {
    bundler.bundle();
  }
}
Copy after login
Use commander to parse the command line and call the bundle method in cli.js

There are three commands: serve, watch, and build to call the bundle function. When executing pracel index.html, the default is serve, so the bundler is called .serve method

Enter Bundler.js

bundler.serve

async serve(port = 1234, https = false, host) {
    this.server = await Server.serve(this, port, host, https);
    try {
      await this.bundle();
    } catch (e) {}
    return this.server;
  }
Copy after login
bundler.serve method calls serveStatic to create a static service pointing to the final packaged folder

below It’s the important bundle method

bundler.bundle

async bundle() {
    // 加载插件 设置env 启动多线程 watcher hmr
    await this.start();

    if (isInitialBundle) {
      // 创建 输出目录
      await fs.mkdirp(this.options.outDir);

      this.entryAssets = new Set();
      for (let entry of this.entryFiles) {
          let asset = await this.resolveAsset(entry);
          this.buildQueue.add(asset);
          this.entryAssets.add(asset);
      }
    }

    // 打包队列中的资源
    let loadedAssets = await this.buildQueue.run();

    // findOrphanAssets 获取所有资源中独立的没有父Bundle的资源
    let changedAssets = [...this.findOrphanAssets(), ...loadedAssets];

    // 因为接下来要构建 Bundle 树,先对上一次的 Bundle树 进行 clear 操作
    for (let asset of this.loadedAssets.values()) {
      asset.invalidateBundle();
    }

    // 构建 Bundle 树
    this.mainBundle = new Bundle();
    for (let asset of this.entryAssets) {
      this.createBundleTree(asset, this.mainBundle);
    }

    // 获取新的最终打包文件的url
    this.bundleNameMap = this.mainBundle.getBundleNameMap(
      this.options.contentHash
    );
    // 将代码中的旧文件url替换为新的
    for (let asset of changedAssets) {
      asset.replaceBundleNames(this.bundleNameMap);
    }

    // 将改变的资源通过websocket发送到浏览器
    if (this.hmr && !isInitialBundle) {
      this.hmr.emitUpdate(changedAssets);
    }

    // 对资源打包
    this.bundleHashes = await this.mainBundle.package(
      this,
      this.bundleHashes
    );

    // 将独立的资源删除
    this.unloadOrphanedAssets();

    return this.mainBundle;
  }
Copy after login
Let’s look at this.start step by step

start

if (this.farm) {
  return;
}

await this.loadPlugins();

if (!this.options.env) {
  await loadEnv(Path.join(this.options.rootDir, 'index'));
  this.options.env = process.env;
}

if (this.options.watch) {
  this.watcher = new Watcher();
  this.watcher.on('change', this.onChange.bind(this));
}

if (this.options.hmr) {
  this.hmr = new HMRServer();
  this.options.hmrPort = await this.hmr.start(this.options);
}

this.farm = await WorkerFarm.getShared(this.options, {
  workerPath: require.resolve('./worker.js')
  });
Copy after login
start:

# The judgment starting with ## prevents multiple executions, that is to say, this.start will only execute loadPlugins once to load the plug-in. Find the plug-in starting with parcel-plugin- in the package.json file dependencies, devDependencies and call loadEnv to load the environment variable. Use dotenv, The dotenv-expand package extends env.development.local, .env.development, .env.local, .env to process.envwatch to initialize the listening file and bind the change callback function. Internally, child_process.fork starts a child process and uses the chokidar package To monitor file changes, hmr starts a service, WebSocket sends the changed resource farm to the browser, initializes multiple processes and specifies the werker working file, and opens multiple child_processes to parse and compile resources.

Next, return to bundle, isInitialBundle is a Determine whether it is the first time to build

fs.mkdirp Create the output folder

Traverse the entry file, through resolveAsset, internally call the resolver to parse the path, and getAsset to obtain the corresponding asset (here our entry is index.html, according to The extension gets HTMLAsset)
Add the asset into the queue
Then start this.buildQueue.run() and start packaging the resources recursively from the entrance

PromiseQueue

here buildQueue It is a PromiseQueue asynchronous queue

PromiseQueue passes in a callback function callback during initialization, maintains a parameter queue queue internally, add pushes a parameter to the queue, and traverses the queue while running callback(...queue.shift( )), the queue is all executed and the Promise is set to completed (resolved) (it can be understood as Promise.all)

The callback function defined here is processAsset, and the parameter is the HTMLAsset of the entry file index.html

async processAsset(asset, isRebuild) {
  if (isRebuild) {
    asset.invalidate();
    if (this.cache) {
      this.cache.invalidate(asset.name);
    }
  }

  await this.loadAsset(asset);
}
Copy after login

processAsset In the function, first determine whether it is a Rebuild, whether it is the first build, or a rebuild performed by watch monitoring file changes. If it is a rebuild, reset the properties of the resource and invalidate its cache Then call loadAsset to load the resource and compile it Resource


loadAsset

async loadAsset(asset) {
    if (asset.processed) {
      return;
    }

    // Mark the asset processed so we don't load it twice
    asset.processed = true;

    // 先尝试读缓存,缓存没有在后台加载和编译
    asset.startTime = Date.now();
    let processed = this.cache && (await this.cache.read(asset.name));
    let cacheMiss = false;
    if (!processed || asset.shouldInvalidate(processed.cacheData)) {
      processed = await this.farm.run(asset.name);
      cacheMiss = true;
    }

    asset.endTime = Date.now();
    asset.buildTime = asset.endTime - asset.startTime;
    asset.id = processed.id;
    asset.generated = processed.generated;
    asset.hash = processed.hash;
    asset.cacheData = processed.cacheData;

    // 解析和加载当前资源的依赖项
    let assetDeps = await Promise.all(
      dependencies.map(async dep => {
          dep.parent = asset.name;
          let assetDep = await this.resolveDep(asset, dep);
          if (assetDep) {
            await this.loadAsset(assetDep);
          }
          return assetDep;
      })
    );

    if (this.cache && cacheMiss) {
      this.cache.write(asset.name, processed);
    }
  }
Copy after login

loadAsset reads the cache after making a judgment at the beginning to prevent repeated compilation

. If the read fails, call this.farm.run to compile the resource in multiple processes

After compilation, load and compile the dependent files
Finally, if the new resource does not use the cache, reset the cache
Let’s talk about the two things involved here: cache FSCache and multi-process WorkerFarm

FSCache

read 读取缓存,并判断最后修改时间和缓存的修改时间
write 写入缓存

Detailed analysis of Parcel source code (with examples)

缓存目录为了加速读取,避免将所有的缓存文件放在一个文件夹里,parcel 将 16进制 两位数的 256 种可能创建为文件夹,这样存取缓存文件的时候,将目标文件路径 md5 加密转换为 16进制,然后截取前两位是目录,后面几位是文件名

WorkerFarm

在上面 start 里初始化 farm 的时候,workerPath 指向了 worker.js 文件,worker.js 里有两个函数,init 和 run
WorkerFarm.getShared 初始化的时候会创建一个 new WorkerFarm ,调用 worker.js 的 init 方法,根据 cpu 获取最大的 Worker 数,并启动一半的子进程
farm.run 会通知子进程执行 worker.js 的 run 方法,如果进程数没有达到最大会再次开启一个新的子进程,子进程执行完毕后将 Promise状态更改为完成
worker.run -> pipeline.process -> pipeline.processAsset -> asset.process
Asset.process 处理资源:

async process() {
    if (!this.generated) {
      await this.loadIfNeeded();
      await this.pretransform();
      await this.getDependencies();
      await this.transform();
      this.generated = await this.generate();
    }

    return this.generated;
  }
Copy after login

将上面的代码内部扩展一下:

async process() {
  // 已经有就不需要编译
  if (!this.generated) {
    // 加载代码
    if (this.contents == null) {
      this.contents = await this.load();
    }
    // 可选。在收集依赖之前转换。
    await this.pretransform();
    // 将代码解析为 AST 树
    if (!this.ast) {
      this.ast = await this.parse(this.contents);
    }
    // 收集依赖
    await this.collectDependencies();
    // 可选。在收集依赖之后转换。
    await this.transform();
    // 生成代码
    this.generated = await this.generate();
  }

  return this.generated;
}

// 最后处理代码
async postProcess(generated) {
  return generated
}
Copy after login

processAsset 中调用 asset.process 生成 generated 这个generated 不一定是最终代码 ,像 html里内联的 script ,vue 的 html, js, css,都会进行二次或多次递归处理,最终调用 asset.postProcess 生成代码

Asset

下面说几个实现

HTMLAsset:

pretransform 调用 posthtml 将 html 解析为 PostHTMLTree(如果没有设置posthtmlrc之类的不会走)

parse 调用 posthtml-parser 将 html 解析为 PostHTMLTree

collectDependencies 用 walk 遍历 ast,找到 script, img 的 src,link 的 href 等的地址,将其加入到依赖

transform htmlnano 压缩代码

generate 处理内联的 script 和 css

postProcess posthtml-render 生成 html 代码

JSAsset:

pretransform 调用 @babel/core 将 js 解析为 AST,处理 process.env

parse 调用 @babel/parser 将 js 解析为 AST

collectDependencies 用 babylon-walk 遍历 ast, 如 ImportDeclaration,import xx from 'xx' 语法,CallExpression 找到 require调用,import 被标记为 dynamic 动态导入,将这些模块加入到依赖

transform 处理 readFileSync,__dirname, __filename, global等,如果没有设置scopeHoist 并存在 es6 module 就将代码转换为 commonjs,terser 压缩代码

generate @babel/generator 获取 js 与 sourceMap 代码

VueAsset:

parse @vue/component-compiler-utils 与 vue-template-compiler 对 .vue 文件进行解析

generate 对 html, js, css 处理,就像上面说到会对其分别调用 processAsset 进行二次解析

postProcess component-compiler-utils 的 compileTemplate, compileStyle处理 html,css,vue-hot-reload-api HMR处理,压缩代码

回到 bundle 方法:

let loadedAssets = await this.buildQueue.run() 就是上面说到的PromiseQueue 和 WorkerFarm 结合起来:buildQueue.run —> processAsset -> loadAsset -> farm.run -> worker.run -> pipeline.process -> pipeline.processAsset -> asset.process,执行之后所有资源编译完毕,并返回入口资源loadedAssets就是 index.html 对应的 HTMLAsset 资源

之后是 let changedAssets = [...this.findOrphanAssets(), ...loadedAssets] 获取到改变的资源

findOrphanAssets 是从所有资源中查找没有 parentBundle 的资源,也就是独立的资源,这个 parentBundle 会在等会的构建 Bundle 树中被赋值,第一次构建都没有 parentBundle,所以这里会重复入口文件,这里的 findOrphanAssets 的作用是在第一次构建之后,文件change的时候,在这个文件 import了新的一个文件,因为新文件没有被构建过 Bundle 树,所以没有 parentBundle,这个新文件也被标记物 change

invalidateBundle 因为接下来要构建新的树所以调用重置所有资源上一次树的属性

createBundleTree 构建 Bundle 树:

首先一个入口资源会被创建成一个 bundle,然后动态的 import() 会被创建成子 bundle ,这引发了代码的拆分。

当不同类型的文件资源被引入,兄弟 bundle 就会被创建。例如你在 JavaScript 中引入了 CSS 文件,那它会被放置在一个与 JavaScript 文件对应的兄弟 bundle 中。

如果资源被多于一个 bundle 引用,它会被提升到 bundle 树中最近的公共祖先中,这样该资源就不会被多次打包。

Bundle:

type:它包含的资源类型 (例如:js, css, map, ...)

name:bundle 的名称 (使用 entryAsset 的 Asset.generateBundleName() 生成)

parentBundle:父 bundle ,入口 bundle 的父 bundle 是 null

entryAsset:bundle 的入口,用于生成名称(name)和聚拢资源(assets)

assets:bundle 中所有资源的集合(Set)

childBundles:所有子 bundle 的集合(Set)

siblingBundles:所有兄弟 bundle 的集合(Set)

siblingBundlesMap:所有兄弟 bundle 的映射 Map

offsets:所有 bundle 中资源位置的映射 Map ,用于生成准确的 sourcemap 。

我们的例子会被构建成:

html            ( index.html )
  |-- js        ( index.js, module1.js, module2.js )
    |-- map     ( index.js, module1.js, module2.js )
Copy after login

module1.js 和 module2.js 被提到了与 index.js 同级,map 因为类型不同被放到了 子bundle

一个复杂点的树:

// 资源树
index.html
  |-- index.css
  |-- bg.png
  |-- index.js
    |-- module.js
Copy after login
// mainBundle
html            ( index.html )
  |-- js        ( index.js, module.js )
    |-- map     ( index.map, module.map )
  |-- css       ( index.css )
    |-- js      ( index.css, css-loader.js bundle-url.js )
    |-- map     ( css-loader.js, bundle-url.js )
  |-- png       ( bg.png )
Copy after login

因为要对 css 热更新,所以新增了 css-loader.js, bundle-url.js 两个 js

replaceBundleNames替换引用:生成树之后将代码中的文件引用替换为最终打包的文件名,如果是生产环境会替换为 contentHash 根据内容生成 hash

hmr更新: 判断启用 hmr 并且不是第一次构建的情况,调用 hmr.emitUpdate 将改变的资源发送给浏览器

Bundle.package 打包

unloadOrphanedAssets 将独立的资源删除

package

package 将generated 写入到文件
有6种打包:
CSSPackager,HTMLPackager,SourceMapPackager,JSPackager,JSConcatPackager,RawPackager
当开启 scopeHoist 时用 JSConcatPackager 否则 JSPackager
图片等资源用 RawPackager

最终我们的例子被打包成 index.html, src.[hash].js, src.[hash].map 3个文件

index.html 里的 js 路径被替换成立最终打包的地址

我们看一下打包的 js:

parcelRequire = (function (modules, cache, entry, globalName) {
  // Save the require from previous bundle to this closure if any
  var previousRequire = typeof parcelRequire === 'function' && parcelRequire;
  var nodeRequire = typeof require === 'function' && require;

  function newRequire(name, jumped) {
    if (!cache[name]) {
      localRequire.resolve = resolve;
      localRequire.cache = {};

      var module = cache[name] = new newRequire.Module(name);

      modules[name][0].call(module.exports, localRequire, module, module.exports, this);
    }

    return cache[name].exports;

    function localRequire(x){
      return newRequire(localRequire.resolve(x));
    }

    function resolve(x){
      return modules[name][4][x] || x;
    }
  }
  for (var i = 0; i <p>可以看到代码被拼接成了对象的形式,接收参数 module, require 用来模块导入导出,实现了 commonjs 的模块加载机制,一个更加简化版:</p><pre class="brush:php;toolbar:false">parcelRequire = (function (modules, cache, entry, globalName) {
  function newRequire(id){
    if(!cache[id]){
      let module = cache[id] = { exports: {} }
      modules[id][0].call(module.exports, newRequire, module, module.exports, this);
    }
    return cache[id]
  }
  for (var i = 0; i <p>代码被拼接起来:</p><pre class="brush:php;toolbar:false">`(function(modules){
  //...newRequire
})({` +
  asset.id +
    ':[function(require,module,exports) {\n' +
        asset.generated.js +
      '\n},' +
'})'
Copy after login
(function(modules){
  //...newRequire
})({
  "src/index.js":[function(require,module,exports){
    // code
  }]
})
Copy after login

hmr-runtime

上面打包的 js 中还有个 hmr-runtime.js 太长被我省略了
hmr-runtime.js 创建一个 WebSocket 监听服务端消息
修改文件触发 onChange 方法,onChange 将改变的资源 buildQueue.add 加入构建队列,重新调用 bundle 方法,打包资源,并调用 emitUpdate 通知浏览器更新
当浏览器接收到服务端有新资源更新消息时
新的资源就会设置或覆盖之前的模块
modules[asset.id] = new Function('require', 'module', 'exports', asset.generated.js)
对模块进行更新:

function hmrAccept(id){
  // dispose 回调
  cached.hot._disposeCallbacks.forEach(function (cb) {
    cb(bundle.hotData);
  });

  delete bundle.cache[id]; // 删除之前缓存
  newRequire(id); // 重新此加载

  // accept 回调
  cached.hot._acceptCallbacks.forEach(function (cb) {
    cb();
  });

  // 递归父模块 进行更新
  getParents(global.parcelRequire, id).some(function (id) {
    return hmrAccept(global.parcelRequire, id);
  });
}
Copy after login

至此整个打包流程结束

总结

parcle index.html
进入 cli,启动Server调用 bundle,初始化配置(Plugins, env, HMRServer, Watcher, WorkerFarm),从入口资源开始,递归编译(babel, posthtml, postcss, vue-template-compiler等),编译完设置缓存,构建 Bundle 树,进行打包
如果没有 watch 监听,结束关闭 Watcher, Worker, HMR
有 watch 监听:
文件修改,触发 onChange,将修改的资源加入构建队列,递归编译,查找缓存(这一步缓存的作用就提醒出来了),编译完设置新缓存,构建 Bundle 树,进行打包,将 change 的资源发送给浏览器,浏览器接收 hmr 更新资源

Packaging tool Time

The above is the detailed content of Detailed analysis of Parcel source code (with examples). For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: How To Unlock Everything In MyRise
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

PHP and Vue: a perfect pairing of front-end development tools PHP and Vue: a perfect pairing of front-end development tools Mar 16, 2024 pm 12:09 PM

PHP and Vue: a perfect pairing of front-end development tools. In today's era of rapid development of the Internet, front-end development has become increasingly important. As users have higher and higher requirements for the experience of websites and applications, front-end developers need to use more efficient and flexible tools to create responsive and interactive interfaces. As two important technologies in the field of front-end development, PHP and Vue.js can be regarded as perfect tools when paired together. This article will explore the combination of PHP and Vue, as well as detailed code examples to help readers better understand and apply these two

Questions frequently asked by front-end interviewers Questions frequently asked by front-end interviewers Mar 19, 2024 pm 02:24 PM

In front-end development interviews, common questions cover a wide range of topics, including HTML/CSS basics, JavaScript basics, frameworks and libraries, project experience, algorithms and data structures, performance optimization, cross-domain requests, front-end engineering, design patterns, and new technologies and trends. . Interviewer questions are designed to assess the candidate's technical skills, project experience, and understanding of industry trends. Therefore, candidates should be fully prepared in these areas to demonstrate their abilities and expertise.

Simple JavaScript Tutorial: How to Get HTTP Status Code Simple JavaScript Tutorial: How to Get HTTP Status Code Jan 05, 2024 pm 06:08 PM

JavaScript tutorial: How to get HTTP status code, specific code examples are required. Preface: In web development, data interaction with the server is often involved. When communicating with the server, we often need to obtain the returned HTTP status code to determine whether the operation is successful, and perform corresponding processing based on different status codes. This article will teach you how to use JavaScript to obtain HTTP status codes and provide some practical code examples. Using XMLHttpRequest

How to display the source code of PHP code in the browser without being interpreted and executed? How to display the source code of PHP code in the browser without being interpreted and executed? Mar 11, 2024 am 10:54 AM

How to display the source code of PHP code in the browser without being interpreted and executed? PHP is a server-side scripting language commonly used to develop dynamic web pages. When a PHP file is requested on the server, the server interprets and executes the PHP code in it and sends the final HTML content to the browser for display. However, sometimes we want to display the source code of the PHP file directly in the browser instead of being executed. This article will introduce how to display the source code of PHP code in the browser without being interpreted and executed. In PHP, you can use

Is Django front-end or back-end? check it out! Is Django front-end or back-end? check it out! Jan 19, 2024 am 08:37 AM

Django is a web application framework written in Python that emphasizes rapid development and clean methods. Although Django is a web framework, to answer the question whether Django is a front-end or a back-end, you need to have a deep understanding of the concepts of front-end and back-end. The front end refers to the interface that users directly interact with, and the back end refers to server-side programs. They interact with data through the HTTP protocol. When the front-end and back-end are separated, the front-end and back-end programs can be developed independently to implement business logic and interactive effects respectively, and data exchange.

Exploring Go language front-end technology: a new vision for front-end development Exploring Go language front-end technology: a new vision for front-end development Mar 28, 2024 pm 01:06 PM

As a fast and efficient programming language, Go language is widely popular in the field of back-end development. However, few people associate Go language with front-end development. In fact, using Go language for front-end development can not only improve efficiency, but also bring new horizons to developers. This article will explore the possibility of using the Go language for front-end development and provide specific code examples to help readers better understand this area. In traditional front-end development, JavaScript, HTML, and CSS are often used to build user interfaces

Website to view source code online Website to view source code online Jan 10, 2024 pm 03:31 PM

You can use the browser's developer tools to view the source code of the website. In the Google Chrome browser: 1. Open the Chrome browser and visit the website where you want to view the source code; 2. Right-click anywhere on the web page and select "Inspect" or press the shortcut key Ctrl + Shift + I to open the developer tools; 3. In the top menu bar of the developer tools, select the "Elements" tab; 4. Just see the HTML and CSS code of the website.

Combination of Golang and front-end technology: explore how Golang plays a role in the front-end field Combination of Golang and front-end technology: explore how Golang plays a role in the front-end field Mar 19, 2024 pm 06:15 PM

Combination of Golang and front-end technology: To explore how Golang plays a role in the front-end field, specific code examples are needed. With the rapid development of the Internet and mobile applications, front-end technology has become increasingly important. In this field, Golang, as a powerful back-end programming language, can also play an important role. This article will explore how Golang is combined with front-end technology and demonstrate its potential in the front-end field through specific code examples. The role of Golang in the front-end field is as an efficient, concise and easy-to-learn

See all articles