Try ERPNext Buy Support Partners Foundation

Tutorial: Adding node modules to Frappe

In some case you might want to add node_modules which can use in custom apps.

My use case is I want to add TinyMCE to blog post doctype.

Steps

  1. Create package.json

    npm init
    
  2. Install package, in my case I want to add tinymce package

    npm i tinymce
    
  3. Run bench build, bench build will

    • Create symbolic link from node_modules to public/node_modules
    • Create assets
      • Note
        • Frappe use rollup.js to create module bundler
        • public folder can be accessible from website url such as http://yourwebsite.com/assets/your_custom_app_name/...
        • build.json should be locate on public folder inside your custom apps
        • You cannot use concat in build.json in your custom apps, since it’s hard coded to run concat only on frappe apps
        • You cannot use import inside doctype js since it need to run through rollup.js frist
        • You could use import inside public folder and then use build.json to bundle the module
        • To manually run rollup.js for your custom apps, you could run /usr/bin/yarn node rollup/build.js --app your_custom_app_name
  4. Adding node_modules to doctype or apps, you need to use hook.py, here is what i did

    • OPTION A

      node_modules = {
      	'tinymce': {
      		'js': [
      			'assets/your_app_name/node_modules/tinymce/tinymce.min.js',
      			'assets/your_app_name/node_modules/tinymce/themes/mobile/theme.min.js',
      			'assets/your_app_name/node_modules/tinymce/themes/silver/theme.min.js',
      			'assets/your_app_name/node_modules/tinymce/icons/default/icons.min.js',
      		],
      	}
      }
      app_include_js = node_modules.get('tinymce').get('js')
      
    • OPTION B

      node_modules = {
      	'tinymce': {
      		'js': [
      			'public/node_modules/tinymce/tinymce.min.js',
      			'public/node_modules/tinymce/themes/mobile/theme.min.js',
      			'public/node_modules/tinymce/themes/silver/theme.min.js',
      			'public/node_modules/tinymce/icons/default/icons.min.js',
      		],
      	}
      }
      
      doctype_js = {
      	'Blog Post': node_modules.get('tinymce').get('js'),
      }
      

      Note
      - This won’t work if module need css, since it will try to access css file from http://yourwebsite.com/... such as http://yourwebsite.com/skins/content/default/content.css
      - JS still won’t work, I think it might be because loading sequence

    • OPTION C

      hook.py

      node_modules = {
      	'tinymce': {
      		'css': [
      			'assets/your_app_name/node_modules/tinymce/skins/ui/oxide/content.min.css',
      			'assets/your_app_name/node_modules/tinymce/skins/content/default/content.css',
      			'assets/your_app_name/node_modules/tinymce/skins/ui/oxide/skin.min.css',
      		]
      	}
      }
      
      app_include_css = node_modules.get('tinymce').get('css')
      

      your doctype js

      frappe.require([
        'assets/your_app_name/node_modules/tinymce/tinymce.min.js',
        'assets/your_app_name/node_modules/tinymce/themes/mobile/theme.min.js',
        'assets/your_app_name/node_modules/tinymce/themes/silver/theme.min.js',
        'assets/your_app_name/node_modules/tinymce/icons/default/icons.min.js',
      ], () => {
        tinymce.init({
      	selector: '#tiny_mce_editor',
      	height: 500,
        });
      });
      

      Note
      - Javascript will still try to access css from http://yourwebsite.com/skins/content/default/content.css but it will work since we’ve adding css to hook.py

Related link
- New Build System: Rollup
- How to add a node module to a custom app?
- https://github.com/frappe/frappe/pull/5010


Please correct me if my understanding is incorrect.

4 Likes